1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#!/usr/bin/env ruby
require 'rbconfig'
require 'mspec/version'
require 'mspec/utils/options'
require 'mspec/utils/name_map'
require 'mspec/helpers/fs'
class MkSpec
attr_reader :config
def initialize
@config = {
:constants => [],
:requires => [],
:base => "core",
:version => nil
}
@map = NameMap.new true
end
def options(argv = ARGV)
options = MSpecOptions.new "mkspec [options]", 32
options.on("-c", "--constant", "CONSTANT",
"Class or Module to generate spec stubs for") do |name|
config[:constants] << name
end
options.on("-b", "--base", "DIR",
"Directory to generate specs into") do |directory|
config[:base] = File.expand_path directory
end
options.on("-r", "--require", "LIBRARY",
"A library to require") do |file|
config[:requires] << file
end
options.on("-V", "--version-guard", "VERSION",
"Specify version for ruby_version_is guards") do |version|
config[:version] = version
end
options.version MSpec::VERSION
options.help
options.doc "\n How might this work in the real world?\n"
options.doc " 1. To create spec stubs for every class or module in Object\n"
options.doc " $ mkspec\n"
options.doc " 2. To create spec stubs for Fixnum\n"
options.doc " $ mkspec -c Fixnum\n"
options.doc " 3. To create spec stubs for Complex in 'superspec/complex'\n"
options.doc " $ mkspec -c Complex -r complex -b superspec"
options.doc ""
options.parse argv
end
def create_directory(mod)
subdir = @map.dir_name mod, config[:base]
if File.exist? subdir
unless File.directory? subdir
puts "#{subdir} already exists and is not a directory."
return nil
end
else
mkdir_p subdir
end
subdir
end
def write_requires(dir, file)
prefix = config[:base] + '/'
raise dir unless dir.start_with? prefix
sub = dir[prefix.size..-1]
parents = '../' * (sub.split('/').length + 1)
File.open(file, 'w') do |f|
f.puts "require_relative '#{parents}spec_helper'"
config[:requires].each do |lib|
f.puts "require '#{lib}'"
end
end
end
def write_version(f)
f.puts ""
if version = config[:version]
f.puts "ruby_version_is #{version} do"
yield " "
f.puts "end"
else
yield ""
end
end
def write_spec(file, meth, exists)
if exists
out = `#{ruby} #{MSPEC_HOME}/bin/mspec-run --dry-run --unguarded -fs -e '#{meth}' #{file}`
return if out.include?(meth)
end
File.open file, 'a' do |f|
write_version(f) do |indent|
f.puts <<-EOS
#{indent}describe "#{meth}" do
#{indent} it "needs to be reviewed for spec completeness"
#{indent}end
EOS
end
end
puts file
end
def create_file(dir, mod, meth, name)
file = File.join dir, @map.file_name(meth, mod)
exists = File.exist? file
write_requires dir, file unless exists
write_spec file, name, exists
end
def run
config[:requires].each { |lib| require lib }
constants = config[:constants]
constants = Object.constants if constants.empty?
@map.map({}, constants).each do |mod, methods|
name = mod.chop
next unless dir = create_directory(name)
methods.each { |method| create_file dir, name, method, mod + method }
end
end
##
# Determine and return the path of the ruby executable.
def ruby
ruby = File.join(RbConfig::CONFIG['bindir'],
RbConfig::CONFIG['ruby_install_name'])
ruby.gsub! File::SEPARATOR, File::ALT_SEPARATOR if File::ALT_SEPARATOR
return ruby
end
def self.main
ENV['MSPEC_RUNNER'] = '1'
script = new
script.options
script.run
end
end
|