pretentious 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +164 -0
- data/Rakefile +1 -0
- data/bin/ddtgen +72 -0
- data/example.rb +93 -0
- data/lib/pretentious.rb +370 -0
- data/lib/pretentious/deconstructor.rb +292 -0
- data/lib/pretentious/rspec_generator.rb +215 -0
- data/lib/pretentious/version.rb +3 -0
- data/pretentious.gemspec +23 -0
- data/run_test.sh +6 -0
- data/spec/fibonacci_spec.rb +66 -0
- data/spec/m_d5_spec.rb +13 -0
- data/spec/spec_helper.rb +63 -0
- data/spec/test_class1_spec.rb +42 -0
- data/spec/test_class2_spec.rb +25 -0
- data/spec/test_class3_spec.rb +51 -0
- data/test/test_generator.rb +105 -0
- data/test_class3_spec.rb +1 -0
- metadata +117 -0
@@ -0,0 +1,292 @@
|
|
1
|
+
class Pretentious::Deconstructor
|
2
|
+
|
3
|
+
class Reference
|
4
|
+
attr_accessor :tree
|
5
|
+
|
6
|
+
def initialize(tree)
|
7
|
+
@tree = tree
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def dfs_array(arr, refs)
|
12
|
+
value = []
|
13
|
+
arr.each { |v|
|
14
|
+
if Pretentious::Deconstructor.is_primitive?(v)
|
15
|
+
value << v
|
16
|
+
elsif v.is_a? Hash
|
17
|
+
value << dfs_hash(v, refs)
|
18
|
+
elsif v.is_a? Array
|
19
|
+
value << dfs_array(v, refs)
|
20
|
+
elsif v.is_a? Reference
|
21
|
+
refs << v.tree[:id]
|
22
|
+
value << Reference.new(dfs(v.tree))
|
23
|
+
elsif value << v
|
24
|
+
end
|
25
|
+
}
|
26
|
+
value
|
27
|
+
end
|
28
|
+
|
29
|
+
def dfs_hash(hash, refs)
|
30
|
+
value = {}
|
31
|
+
hash.each { |k, v|
|
32
|
+
if Pretentious::Deconstructor.is_primitive?(v)
|
33
|
+
value[k] = v
|
34
|
+
elsif v.is_a? Hash
|
35
|
+
value[k] = dfs_hash(v, refs)
|
36
|
+
elsif v.is_a? Array
|
37
|
+
value[k] = dfs_array(v, refs)
|
38
|
+
elsif v.is_a? Reference
|
39
|
+
refs << v.tree[:id]
|
40
|
+
value[k] = Reference.new(dfs(v.tree))
|
41
|
+
else
|
42
|
+
value[k] = v
|
43
|
+
end
|
44
|
+
}
|
45
|
+
value
|
46
|
+
end
|
47
|
+
|
48
|
+
def dfs(tree)
|
49
|
+
if !tree.is_a? Hash
|
50
|
+
value = tree
|
51
|
+
definition = {id: value.object_id, class: tree.class, value: value}
|
52
|
+
unless (@dependencies.include? value.object_id)
|
53
|
+
@dependencies[value.object_id] = definition
|
54
|
+
@declaration_order << definition
|
55
|
+
end
|
56
|
+
value.object_id
|
57
|
+
else
|
58
|
+
ref = []
|
59
|
+
|
60
|
+
definition = {id: tree[:id], class: tree[:class]}
|
61
|
+
|
62
|
+
if tree[:class] == Hash
|
63
|
+
definition[:value] = dfs_hash(tree[:composition], ref)
|
64
|
+
elsif tree[:class] == Array
|
65
|
+
definition[:value] = dfs_array(tree[:composition], ref)
|
66
|
+
elsif tree[:composition].is_a? Array
|
67
|
+
tree[:composition].each { |t|
|
68
|
+
ref << dfs(t)
|
69
|
+
}
|
70
|
+
else
|
71
|
+
ref << dfs(tree[:composition])
|
72
|
+
end
|
73
|
+
|
74
|
+
definition[:ref] = ref
|
75
|
+
|
76
|
+
unless (@dependencies.include? tree[:id])
|
77
|
+
@declaration_order << definition
|
78
|
+
@dependencies[tree[:id]] = definition
|
79
|
+
end
|
80
|
+
tree[:id]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def deconstruct(*target_objects)
|
85
|
+
|
86
|
+
@declaration_order = []
|
87
|
+
@dependencies = {}
|
88
|
+
|
89
|
+
target_objects.each { |target_object|
|
90
|
+
tree = build_tree target_object
|
91
|
+
dfs(tree)
|
92
|
+
}
|
93
|
+
|
94
|
+
{declaration: @declaration_order, dependency: @dependencies}
|
95
|
+
end
|
96
|
+
|
97
|
+
def deconstruct_to_ruby(indentation_level = 0, variable_map = {}, declared_names = {}, *target_objects)
|
98
|
+
output_buffer = ""
|
99
|
+
indentation = ""
|
100
|
+
|
101
|
+
indentation_level.times {
|
102
|
+
indentation << ' '
|
103
|
+
}
|
104
|
+
|
105
|
+
target_objects.each { |target_object|
|
106
|
+
variable_map.merge!(target_object._variable_map) if target_object.methods.include?(:_variable_map) && !target_object._variable_map.nil?
|
107
|
+
}
|
108
|
+
|
109
|
+
declarations, dependencies = deconstruct *target_objects
|
110
|
+
declarations[:declaration].each do |d|
|
111
|
+
|
112
|
+
var_name = Pretentious::Deconstructor.pick_name(variable_map, d[:id], declared_names)
|
113
|
+
output_buffer << "#{indentation}#{var_name} = #{construct(d, variable_map, declared_names)}\n"
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
output_buffer
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.is_primitive?(value)
|
121
|
+
value.is_a?(String) || value.is_a?(Fixnum) || value.is_a?(TrueClass) || value.is_a?(FalseClass) ||
|
122
|
+
value.is_a?(NilClass) || value.is_a?(Symbol)
|
123
|
+
end
|
124
|
+
|
125
|
+
def deconstruct_array(array)
|
126
|
+
composition = []
|
127
|
+
array.each { |v|
|
128
|
+
if (Pretentious::Deconstructor.is_primitive?(v))
|
129
|
+
composition << v
|
130
|
+
elsif v.is_a? Hash
|
131
|
+
composition << deconstruct_hash(v)
|
132
|
+
elsif v.is_a? Array
|
133
|
+
composition << deconstruct_array(v)
|
134
|
+
else
|
135
|
+
composition << Reference.new(build_tree(v))
|
136
|
+
end
|
137
|
+
}
|
138
|
+
composition
|
139
|
+
end
|
140
|
+
|
141
|
+
def deconstruct_hash(hash)
|
142
|
+
composition = {}
|
143
|
+
hash.each { |k, v|
|
144
|
+
if (Pretentious::Deconstructor.is_primitive?(v))
|
145
|
+
composition[k] = v
|
146
|
+
elsif v.is_a? Hash
|
147
|
+
composition[k] = deconstruct_hash(v)
|
148
|
+
elsif v.is_a? Array
|
149
|
+
composition[k] = deconstruct_array(v)
|
150
|
+
else
|
151
|
+
composition[k] = Reference.new(build_tree(v))
|
152
|
+
end
|
153
|
+
}
|
154
|
+
composition
|
155
|
+
end
|
156
|
+
|
157
|
+
def get_test_class(target_object)
|
158
|
+
target_object.respond_to?(:test_class) ? target_object.test_class : target_object.class
|
159
|
+
end
|
160
|
+
|
161
|
+
#creates a tree on how the object was created
|
162
|
+
def build_tree(target_object)
|
163
|
+
|
164
|
+
tree = {class: get_test_class(target_object), id: target_object.object_id, composition: []}
|
165
|
+
if (target_object.is_a? Array)
|
166
|
+
tree[:composition] = deconstruct_array(target_object)
|
167
|
+
elsif target_object.is_a? Hash
|
168
|
+
tree[:composition] = deconstruct_hash(target_object)
|
169
|
+
elsif target_object.methods.include? :_get_init_arguments
|
170
|
+
|
171
|
+
args = target_object._get_init_arguments
|
172
|
+
unless args.nil?
|
173
|
+
args[:params].each { |p|
|
174
|
+
tree[:composition] << build_tree(p)
|
175
|
+
}
|
176
|
+
|
177
|
+
else
|
178
|
+
tree[:composition] = target_object
|
179
|
+
end
|
180
|
+
else
|
181
|
+
tree[:composition] = target_object
|
182
|
+
end
|
183
|
+
tree
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.pick_name(variable_map, object_id, declared_names = {})
|
187
|
+
var_name = "var_#{object_id}"
|
188
|
+
|
189
|
+
object_id_to_declared_names = {}
|
190
|
+
|
191
|
+
declared_names.each { |k,v|
|
192
|
+
object_id_to_declared_names[v[:object_id]] = k
|
193
|
+
} if declared_names
|
194
|
+
|
195
|
+
#return immediately if already mapped
|
196
|
+
return object_id_to_declared_names[object_id] if (object_id_to_declared_names.include? object_id)
|
197
|
+
|
198
|
+
if (!variable_map.nil? && variable_map.include?(object_id))
|
199
|
+
|
200
|
+
candidate_name = variable_map[object_id].to_s
|
201
|
+
|
202
|
+
if !declared_names.include?(candidate_name)
|
203
|
+
var_name = candidate_name
|
204
|
+
declared_names[candidate_name] = {count: 1, object_id: object_id}
|
205
|
+
else
|
206
|
+
|
207
|
+
if (declared_names[candidate_name][:object_id] == object_id)
|
208
|
+
var_name = candidate_name
|
209
|
+
else
|
210
|
+
new_name = "#{candidate_name}_#{declared_names[candidate_name][:count]}"
|
211
|
+
var_name = "#{new_name}"
|
212
|
+
|
213
|
+
declared_names[candidate_name][:count]+=1
|
214
|
+
declared_names[new_name] = {count: 1, object_id: object_id}
|
215
|
+
end
|
216
|
+
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
var_name
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
|
226
|
+
def output_array(arr, variable_map, declared_names)
|
227
|
+
output_buffer = '['
|
228
|
+
array_elements = []
|
229
|
+
arr.each { |v|
|
230
|
+
value = Pretentious::value_ize(v, variable_map, declared_names)
|
231
|
+
if (v.is_a? Hash)
|
232
|
+
value = output_hash(v, variable_map, declared_names)
|
233
|
+
elsif (v.is_a? Array)
|
234
|
+
value = output_array(v, variable_map, declared_names)
|
235
|
+
elsif (v.is_a? Reference)
|
236
|
+
value = Pretentious::Deconstructor.pick_name(variable_map, v.tree, declared_names)
|
237
|
+
end
|
238
|
+
array_elements << value
|
239
|
+
}
|
240
|
+
output_buffer << array_elements.join(', ')
|
241
|
+
output_buffer << ']'
|
242
|
+
output_buffer
|
243
|
+
end
|
244
|
+
|
245
|
+
def output_hash(hash, variable_map, declared_names)
|
246
|
+
output_buffer = '{'
|
247
|
+
hash_elements = []
|
248
|
+
hash.each { |k, v|
|
249
|
+
value = Pretentious::value_ize(v, variable_map, declared_names)
|
250
|
+
if (v.is_a? Hash)
|
251
|
+
value = output_hash(v, variable_map, declared_names)
|
252
|
+
elsif (v.is_a? Array)
|
253
|
+
value = output_array(v, variable_map, declared_names)
|
254
|
+
elsif (v.is_a? Reference)
|
255
|
+
value = Pretentious::Deconstructor.pick_name(variable_map, v.tree, declared_names)
|
256
|
+
end
|
257
|
+
|
258
|
+
if (k.is_a? Symbol)
|
259
|
+
hash_elements << "#{k}: #{value}"
|
260
|
+
else
|
261
|
+
hash_elements << "#{Pretentious::value_ize(k, variable_map, declared_names)} => #{value}"
|
262
|
+
end
|
263
|
+
}
|
264
|
+
output_buffer << hash_elements.join(', ')
|
265
|
+
output_buffer << '}'
|
266
|
+
output_buffer
|
267
|
+
end
|
268
|
+
|
269
|
+
def construct(definition, variable_map, declared_names)
|
270
|
+
if (definition[:value])
|
271
|
+
if (definition[:value].is_a? Hash)
|
272
|
+
output_hash(definition[:value], variable_map, declared_names)
|
273
|
+
elsif (definition[:value].is_a? Array)
|
274
|
+
output_array(definition[:value], variable_map, declared_names)
|
275
|
+
else
|
276
|
+
Pretentious::value_ize(definition[:value], variable_map, declared_names)
|
277
|
+
end
|
278
|
+
else
|
279
|
+
params = []
|
280
|
+
if (definition[:ref].size > 0)
|
281
|
+
definition[:ref].each do |v|
|
282
|
+
params << Pretentious::Deconstructor.pick_name(variable_map,v, declared_names)
|
283
|
+
end
|
284
|
+
"#{definition[:class]}.new(#{params.join(', ')})"
|
285
|
+
else
|
286
|
+
"#{definition[:class]}.new"
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
class Pretentious::RspecGenerator
|
2
|
+
|
3
|
+
def initialize(options = {})
|
4
|
+
@deconstructor = Pretentious::Deconstructor.new
|
5
|
+
indentation_count = options[:indentation] || 2
|
6
|
+
@output_buffer = ""
|
7
|
+
@_indentation = ""
|
8
|
+
indentation_count.times do
|
9
|
+
@_indentation << " "
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def indentation(level)
|
14
|
+
buffer = ""
|
15
|
+
level.times do
|
16
|
+
buffer << @_indentation
|
17
|
+
end
|
18
|
+
buffer
|
19
|
+
end
|
20
|
+
|
21
|
+
def buffer(line, level = 0)
|
22
|
+
@output_buffer << "#{indentation(level)}#{line}\n"
|
23
|
+
end
|
24
|
+
|
25
|
+
def whitespace(level = 0)
|
26
|
+
@output_buffer << "#{indentation(level)}\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
def begin_spec(test_class)
|
30
|
+
buffer("require 'spec_helper'")
|
31
|
+
whitespace
|
32
|
+
buffer("RSpec.describe #{test_class.name} do")
|
33
|
+
whitespace
|
34
|
+
end
|
35
|
+
|
36
|
+
def end_spec
|
37
|
+
buffer("end")
|
38
|
+
end
|
39
|
+
|
40
|
+
def output
|
41
|
+
@output_buffer
|
42
|
+
end
|
43
|
+
|
44
|
+
def generate(test_instance, instance_count)
|
45
|
+
if (test_instance.is_a? Class)
|
46
|
+
#class methods
|
47
|
+
class_method_calls = test_instance.method_calls_by_method
|
48
|
+
generate_specs("#{test_instance.test_class.name}::",test_instance.test_class.name, class_method_calls, test_instance.let_variables)
|
49
|
+
else
|
50
|
+
buffer("context 'Scenario #{instance_count}' do",1)
|
51
|
+
|
52
|
+
buffer("before do",2)
|
53
|
+
whitespace
|
54
|
+
args = test_instance._init_arguments[:params]
|
55
|
+
declarations = {}
|
56
|
+
buffer(declare_dependencies(args, test_instance.init_let_variables, 3 * @_indentation.length, declarations))
|
57
|
+
if (args.size > 0)
|
58
|
+
buffer("@fixture = #{test_instance.test_class.name}.new(#{params_generator(args, test_instance.init_let_variables, declarations)})",3)
|
59
|
+
else
|
60
|
+
buffer("@fixture = #{test_instance.test_class.name}.new",3)
|
61
|
+
end
|
62
|
+
whitespace
|
63
|
+
buffer("end",2)
|
64
|
+
whitespace
|
65
|
+
|
66
|
+
method_calls = test_instance.method_calls_by_method
|
67
|
+
|
68
|
+
generate_specs("#{test_instance.test_class.name}#","@fixture",method_calls, test_instance.let_variables)
|
69
|
+
|
70
|
+
buffer('end',1)
|
71
|
+
whitespace
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def generate_expectation(fixture, method, let_variables, declarations, params, result)
|
79
|
+
statement = if params.size > 0
|
80
|
+
"#{fixture}.#{method.to_s}(#{params_generator(params, let_variables, declarations)})"
|
81
|
+
else
|
82
|
+
"#{fixture}.#{method.to_s}"
|
83
|
+
end
|
84
|
+
|
85
|
+
if (result.kind_of? Exception)
|
86
|
+
buffer("expect { #{statement} }.to #{pick_matcher(result)}",3)
|
87
|
+
else
|
88
|
+
buffer("expect( #{statement} ).to #{pick_matcher(result)}",3)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def generate_specs(context_prefix, fixture, method_calls, let_variables)
|
93
|
+
buffer("it 'should pass current expectations' do",2)
|
94
|
+
whitespace
|
95
|
+
declaration = {}
|
96
|
+
#collect all params
|
97
|
+
params_collection = []
|
98
|
+
|
99
|
+
method_calls.each_key do |k|
|
100
|
+
info_blocks_arr = method_calls[k]
|
101
|
+
info_blocks_arr.each do |block|
|
102
|
+
params_collection = params_collection | block[:params]
|
103
|
+
if (!Pretentious::Deconstructor.is_primitive?(block[:result]) && !block[:result].kind_of?(Exception))
|
104
|
+
params_collection << block[:result]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
buffer(declare_dependencies(params_collection, let_variables, 3 * @_indentation.length, declaration))
|
110
|
+
|
111
|
+
method_calls.each_key do |k|
|
112
|
+
info_blocks_arr = method_calls[k]
|
113
|
+
|
114
|
+
info_blocks_arr.each do |block|
|
115
|
+
|
116
|
+
buffer("# #{context_prefix}#{k} when passed #{desc_params(block)} should return #{block[:result]}", 3)
|
117
|
+
generate_expectation(fixture, k, let_variables, declaration, block[:params], block[:result])
|
118
|
+
|
119
|
+
whitespace
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
end
|
124
|
+
buffer("end",2)
|
125
|
+
end
|
126
|
+
|
127
|
+
#def generate_specs(context_prefix, fixture, method_calls, let_variables)
|
128
|
+
# method_calls.each_key do |k|
|
129
|
+
# info_blocks_arr = method_calls[k]
|
130
|
+
#
|
131
|
+
# buffer("context \"#{context_prefix}#{k}\" do", 1)
|
132
|
+
#
|
133
|
+
# whitespace
|
134
|
+
# info_blocks_arr.each do |block|
|
135
|
+
# buffer("it '#{desc_params(block)} returns #{block[:result]}' do",2)
|
136
|
+
# whitespace
|
137
|
+
# if block[:params].size > 0
|
138
|
+
# buffer(declare_dependencies(block[:params], let_variables, 3))
|
139
|
+
# buffer("expect(#{fixture}.#{k.to_s}(#{params_generator(block[:params], let_variables)})).to #{pick_matcher(block[:result])}",3)
|
140
|
+
# else
|
141
|
+
# buffer("expect(#{fixture}.#{k.to_s}).to #{pick_matcher(block[:result])}",3)
|
142
|
+
# end
|
143
|
+
# whitespace
|
144
|
+
# buffer("end",2)
|
145
|
+
# whitespace
|
146
|
+
# end
|
147
|
+
#
|
148
|
+
# buffer("end", 1)
|
149
|
+
# whitespace
|
150
|
+
# end
|
151
|
+
#end
|
152
|
+
|
153
|
+
def pick_matcher(result)
|
154
|
+
if result.is_a? TrueClass
|
155
|
+
'be true'
|
156
|
+
elsif result.is_a? FalseClass
|
157
|
+
'be false'
|
158
|
+
elsif result.nil?
|
159
|
+
'be_nil'
|
160
|
+
elsif result.kind_of? Exception
|
161
|
+
'raise_error'
|
162
|
+
else
|
163
|
+
"eq(#{Pretentious::value_ize(result, nil, nil)})"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
|
169
|
+
def desc_params(block)
|
170
|
+
params = []
|
171
|
+
args = block[:params]
|
172
|
+
names = block[:names]
|
173
|
+
n = 0
|
174
|
+
#puts args.inspect
|
175
|
+
return "" if args.nil?
|
176
|
+
|
177
|
+
args.each do |arg|
|
178
|
+
param_name = names[n][1].to_s
|
179
|
+
arg_value = (arg.is_a? String) ? "#{arg.dump}" : "#{arg.to_s}"
|
180
|
+
if (param_name.empty?)
|
181
|
+
params << "#{arg_value}"
|
182
|
+
else
|
183
|
+
params << "#{param_name} = #{arg_value}"
|
184
|
+
end
|
185
|
+
|
186
|
+
n+=1
|
187
|
+
end
|
188
|
+
params.join(" ,")
|
189
|
+
end
|
190
|
+
|
191
|
+
def declare_dependencies(args, variable_map, level, declarations)
|
192
|
+
deconstructor = Pretentious::Deconstructor.new
|
193
|
+
|
194
|
+
args = remove_primitives(args, variable_map)
|
195
|
+
deconstructor.deconstruct_to_ruby(level, variable_map, declarations, *args)
|
196
|
+
end
|
197
|
+
|
198
|
+
def remove_primitives(args, let_lookup)
|
199
|
+
args.select { |a| let_lookup.include?(a.object_id) || !Pretentious::Deconstructor.is_primitive?(a) }
|
200
|
+
end
|
201
|
+
|
202
|
+
def params_generator(args, let_variables, declared_names)
|
203
|
+
params = []
|
204
|
+
args.each do |arg|
|
205
|
+
if (!let_variables.nil? && let_variables[arg.object_id])
|
206
|
+
params << Pretentious::Deconstructor.pick_name(let_variables, arg.object_id, declared_names)
|
207
|
+
else
|
208
|
+
params << Pretentious::value_ize(arg, let_variables, declared_names)
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
params.join(", ")
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|