active_mocker 2.4.0.pre5 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +27 -3
- data/lib/active_mocker.rb +7 -0
- data/lib/active_mocker/file_writer.rb +2 -2
- data/lib/active_mocker/loaded_mocks/features.rb +10 -3
- data/lib/active_mocker/mock/base.rb +8 -0
- data/lib/active_mocker/mock/do_nothing_active_record_methods.rb +1 -1
- data/lib/active_mocker/mock/exceptions.rb +2 -0
- data/lib/active_mocker/mock_creator.rb +32 -322
- data/lib/active_mocker/mock_creator/associations.rb +30 -0
- data/lib/active_mocker/mock_creator/attributes.rb +62 -0
- data/lib/active_mocker/mock_creator/class_methods.rb +53 -0
- data/lib/active_mocker/mock_creator/defined_methods.rb +60 -0
- data/lib/active_mocker/mock_creator/modules_constants.rb +67 -0
- data/lib/active_mocker/mock_creator/recreate_class_method_calls.rb +24 -0
- data/lib/active_mocker/mock_creator/scopes.rb +15 -0
- data/lib/active_mocker/mock_template.erb +1 -1
- data/lib/active_mocker/mock_template/_class_methods.erb +3 -1
- data/lib/active_mocker/mock_template/_scopes.erb +1 -1
- data/lib/active_mocker/rspec_helper.rb +3 -1
- data/lib/active_mocker/version.rb +1 -1
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a77d43b16f10346cb55967ea8dcb22e2f0e3474d
|
4
|
+
data.tar.gz: d6b4efa5cff2e6a9f3c60ff80120ca9a7b1473d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8f488dc87b52e8ee02a96a3e1428d38fddaa37601cdf666667f6ee0dc569a18989a8a5d0ca5dcdfb1f31e92d519d767d440a3b2efbb2b6e8b070d91628c3b89
|
7
|
+
data.tar.gz: 69d308aa84a28cc683d063cda2483f0051055748476de80e811b6fda30bc852835e6d7845e701d0bf87aeb11e59ac97df0f687d3fb1839cb8de29d5859c55abf
|
data/README.md
CHANGED
@@ -196,13 +196,38 @@ Use theses defaults if you are starting fresh
|
|
196
196
|
```ruby
|
197
197
|
ActiveMocker::LoadedMocks.features.enable(:timestamps)
|
198
198
|
ActiveMocker::LoadedMocks.features.enable(:delete_all_before_example)
|
199
|
+
ActiveMocker::LoadedMocks.features.enable(:stub_active_record_exceptions)
|
199
200
|
```
|
200
201
|
|
201
202
|
### timestamps
|
202
|
-
|
203
|
+
|
204
|
+
Enables created_at and updated_at to be update on save and create
|
203
205
|
|
204
206
|
### delete_all_before_example
|
205
|
-
|
207
|
+
|
208
|
+
When using "active_mocker/rspec_helper" it delete all records from all mocks before each example.
|
209
|
+
|
210
|
+
### stub_active_record_exceptions
|
211
|
+
|
212
|
+
When requiring "active_mocker/rspec_helper", and adding `active_mocker: true` to the describe metadata, these errors will be auto stubbed:
|
213
|
+
|
214
|
+
* ActiveRecord::RecordNotFound
|
215
|
+
* ActiveRecord::RecordNotUnique
|
216
|
+
* ActiveRecord::UnknownAttributeError
|
217
|
+
|
218
|
+
### Copy over Mock safe methods into the generated mock
|
219
|
+
|
220
|
+
Adding the comment `ActiveMocker.safe_methods` at the top of a class marks it as safe to copy to the mock.
|
221
|
+
Be careful that it does not contain anything that ActiveMocker cannot run.
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
# ActiveMocker.safe_methods :full_name
|
225
|
+
class User
|
226
|
+
def full_name
|
227
|
+
"#{first_name} + #{last_name}
|
228
|
+
end
|
229
|
+
end
|
230
|
+
```
|
206
231
|
|
207
232
|
## Mocking Methods
|
208
233
|
|
@@ -382,7 +407,6 @@ See [Documentation](http://rdoc.info/github/zeisler/active_mocker/master/ActiveM
|
|
382
407
|
* create_< association >!
|
383
408
|
* < association >.create
|
384
409
|
* < association >.build
|
385
|
-
|
386
410
|
|
387
411
|
### Schema/Migration Option Support
|
388
412
|
* A db/schema.rb is not required.
|
data/lib/active_mocker.rb
CHANGED
@@ -25,6 +25,13 @@ require "active_mocker/progress"
|
|
25
25
|
require "active_mocker/parent_class"
|
26
26
|
require "active_mocker/template_creator"
|
27
27
|
require "active_mocker/mock_creator"
|
28
|
+
require "active_mocker/mock_creator/associations"
|
29
|
+
require "active_mocker/mock_creator/attributes"
|
30
|
+
require "active_mocker/mock_creator/class_methods"
|
31
|
+
require "active_mocker/mock_creator/defined_methods"
|
32
|
+
require "active_mocker/mock_creator/modules_constants"
|
33
|
+
require "active_mocker/mock_creator/recreate_class_method_calls"
|
34
|
+
require "active_mocker/mock_creator/scopes"
|
28
35
|
require "active_mocker/error_object"
|
29
36
|
require "active_mocker/display_errors"
|
30
37
|
require "active_mocker/generate"
|
@@ -98,9 +98,9 @@ module ActiveMocker
|
|
98
98
|
|
99
99
|
def enabled_partials
|
100
100
|
if config.disable_modules_and_constants
|
101
|
-
MockCreator
|
101
|
+
MockCreator::ENABLED_PARTIALS_DEFAULT - [*:modules_constants]
|
102
102
|
else
|
103
|
-
MockCreator
|
103
|
+
MockCreator::ENABLED_PARTIALS_DEFAULT
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
@@ -1,13 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "singleton"
|
3
|
+
require "active_mocker/mock/exceptions"
|
3
4
|
|
4
5
|
module ActiveMocker
|
5
6
|
class LoadedMocks
|
6
7
|
class Features
|
7
8
|
include Singleton
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
STUB_ACTIVE_RECORD_EXCEPTIONS = {
|
10
|
+
"ActiveRecord::RecordNotFound" => ActiveMocker::RecordNotFound,
|
11
|
+
"ActiveRecord::RecordNotUnique" => ActiveMocker::RecordNotUnique,
|
12
|
+
"ActiveRecord::UnknownAttributeError" => ActiveMocker::UnknownAttributeError,
|
13
|
+
}
|
14
|
+
DEFAULTS = {
|
15
|
+
timestamps: false,
|
16
|
+
delete_all_before_example: false,
|
17
|
+
stub_active_record_exceptions: STUB_ACTIVE_RECORD_EXCEPTIONS,
|
11
18
|
}.freeze
|
12
19
|
|
13
20
|
def initialize
|
@@ -133,6 +133,14 @@ module ActiveMocker
|
|
133
133
|
associations_by_class[klass_name.to_s]
|
134
134
|
end
|
135
135
|
|
136
|
+
# Not fully Implemented
|
137
|
+
# Returns association reflections names with nil values
|
138
|
+
#
|
139
|
+
# #=> { "user" => nil, "order" => nil }
|
140
|
+
def reflections
|
141
|
+
associations.each_with_object({}) { |(k, _), h| h[k.to_s] = nil }
|
142
|
+
end
|
143
|
+
|
136
144
|
private
|
137
145
|
|
138
146
|
def created_with(version)
|
@@ -1,11 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
2
|
require "active_mocker/inspectable"
|
4
3
|
|
5
4
|
module ActiveMocker
|
6
5
|
class MockCreator
|
7
|
-
|
8
6
|
using ActiveMocker::Inspectable
|
7
|
+
ENABLED_PARTIALS_DEFAULT = [
|
8
|
+
:modules_constants,
|
9
|
+
:class_methods,
|
10
|
+
:attributes,
|
11
|
+
:scopes,
|
12
|
+
:recreate_class_method_calls,
|
13
|
+
:defined_methods,
|
14
|
+
:associations,
|
15
|
+
].freeze
|
16
|
+
|
9
17
|
def initialize(file:,
|
10
18
|
file_out:,
|
11
19
|
schema_scrapper:,
|
@@ -21,7 +29,7 @@ module ActiveMocker
|
|
21
29
|
@schema_scrapper = schema_scrapper
|
22
30
|
@template_creator = template_creator || template_creator_default(file_out)
|
23
31
|
@class_introspector = class_introspector || class_introspector_default
|
24
|
-
@enabled_partials = enabled_partials ||
|
32
|
+
@enabled_partials = enabled_partials || ENABLED_PARTIALS_DEFAULT
|
25
33
|
@klasses_to_be_mocked = klasses_to_be_mocked
|
26
34
|
@active_record_base_klass = active_record_base_klass
|
27
35
|
@mock_append_name = mock_append_name
|
@@ -32,18 +40,19 @@ module ActiveMocker
|
|
32
40
|
|
33
41
|
def create
|
34
42
|
verify_class
|
35
|
-
if errors.empty?
|
36
|
-
begin
|
37
|
-
template_creator.render
|
38
|
-
rescue => e
|
39
|
-
raise e unless error_already_collected?(e)
|
40
|
-
end
|
41
|
-
file_out.close
|
42
|
-
@completed = true
|
43
|
-
end
|
43
|
+
render { file_out.close } if errors.empty?
|
44
44
|
self
|
45
45
|
end
|
46
46
|
|
47
|
+
def render
|
48
|
+
template_creator.render
|
49
|
+
rescue => e
|
50
|
+
raise e unless error_already_collected?(e)
|
51
|
+
ensure
|
52
|
+
yield
|
53
|
+
@completed = true
|
54
|
+
end
|
55
|
+
|
47
56
|
def completed?
|
48
57
|
@completed
|
49
58
|
end
|
@@ -60,7 +69,8 @@ module ActiveMocker
|
|
60
69
|
:enabled_partials,
|
61
70
|
:klasses_to_be_mocked,
|
62
71
|
:active_record_base_klass,
|
63
|
-
:mock_append_name
|
72
|
+
:mock_append_name,
|
73
|
+
:active_record_model
|
64
74
|
|
65
75
|
def error_already_collected?(e)
|
66
76
|
errors.any? { |eo| eo.original_error == e }
|
@@ -84,37 +94,20 @@ module ActiveMocker
|
|
84
94
|
DissociatedIntrospection::Inspection.new(file: file)
|
85
95
|
end
|
86
96
|
|
87
|
-
|
88
|
-
def enabled_partials_default
|
89
|
-
[
|
90
|
-
:modules_constants,
|
91
|
-
:class_methods,
|
92
|
-
:attributes,
|
93
|
-
:scopes,
|
94
|
-
:recreate_class_method_calls,
|
95
|
-
:defined_methods,
|
96
|
-
:associations,
|
97
|
-
]
|
98
|
-
end
|
97
|
+
# -- END defaults -- #
|
99
98
|
|
100
|
-
|
99
|
+
def parent_class_inspector
|
100
|
+
@parent_class_inspector ||= ParentClass.new(parsed_source: class_introspector.parsed_source,
|
101
|
+
klasses_to_be_mocked: klasses_to_be_mocked,
|
102
|
+
mock_append_name: mock_append_name).call
|
101
103
|
end
|
102
104
|
|
103
|
-
|
104
|
-
|
105
|
-
def parent_class_constant
|
106
|
-
v = ParentClass.new(parsed_source: class_introspector.parsed_source,
|
107
|
-
klasses_to_be_mocked: klasses_to_be_mocked,
|
108
|
-
mock_append_name: mock_append_name).call
|
109
|
-
@parent_class_constant = v.parent_class
|
105
|
+
def verify_parent_class
|
106
|
+
errors << parent_class_inspector.error if parent_class_inspector.error
|
110
107
|
end
|
111
108
|
|
112
109
|
def verify_class
|
113
|
-
|
114
|
-
klasses_to_be_mocked: klasses_to_be_mocked,
|
115
|
-
mock_append_name: mock_append_name).call
|
116
|
-
errors << v.error if v.error
|
117
|
-
@parent_class = v.parent_mock_name
|
110
|
+
verify_parent_class
|
118
111
|
end
|
119
112
|
|
120
113
|
public
|
@@ -123,7 +116,7 @@ module ActiveMocker
|
|
123
116
|
OpenStruct.new(enabled_partials.each_with_object({}) do |p, hash|
|
124
117
|
begin
|
125
118
|
file = File.new(File.join(File.dirname(__FILE__), "mock_template/_#{p}.erb"))
|
126
|
-
extend(
|
119
|
+
extend(ActiveMocker::MockCreator.const_get(p.to_s.camelize))
|
127
120
|
hash[p] = ERB.new(file.read, nil, "-", "_sub#{p}").result(binding)
|
128
121
|
rescue => e
|
129
122
|
errors << ErrorObject.new(class_name: class_name,
|
@@ -150,291 +143,8 @@ module ActiveMocker
|
|
150
143
|
end
|
151
144
|
end
|
152
145
|
|
153
|
-
attr_reader :parent_class, :active_record_model
|
154
|
-
|
155
146
|
def primary_key
|
156
147
|
@primary_key ||= ActiveRecordSchemaScrapper::Attribute.new(name: "id", type: :integer)
|
157
148
|
end
|
158
|
-
|
159
|
-
module ModulesConstants
|
160
|
-
require "active_mocker/mock/unrepresentable_const_value"
|
161
|
-
|
162
|
-
class Inspectable
|
163
|
-
attr_reader :inspect
|
164
|
-
|
165
|
-
def initialize(inspect)
|
166
|
-
@inspect = inspect
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def constants
|
171
|
-
class_introspector.get_class.constants.each_with_object({}) do |v, const|
|
172
|
-
c = class_introspector.get_class.const_get(v)
|
173
|
-
next if [Module, Class].include?(c.class)
|
174
|
-
if /\A#</ =~ c.inspect
|
175
|
-
const[v] = Inspectable.new("ActiveMocker::UNREPRESENTABLE_CONST_VALUE")
|
176
|
-
else
|
177
|
-
const[v] = c
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
def modules
|
183
|
-
@modules ||= begin
|
184
|
-
{
|
185
|
-
included: get_module_by_reference(:included_modules),
|
186
|
-
extended: get_module_by_reference(:extended_modules),
|
187
|
-
}
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
private
|
192
|
-
|
193
|
-
def get_module_by_reference(type)
|
194
|
-
isolated_module_names = reject_local_const(class_introspector.public_send(type)).map(&:referenced_name)
|
195
|
-
real_module_names = get_real_module(type).map(&:name).compact
|
196
|
-
isolated_module_names.map do |isolated_name|
|
197
|
-
real_name = real_module_names.detect do |rmn|
|
198
|
-
real_parts = rmn.split("::")
|
199
|
-
total_parts_count = active_record_model.name.split("::").count + isolated_name.split("::").count
|
200
|
-
[
|
201
|
-
real_parts.include?(active_record_model.name),
|
202
|
-
real_parts.include?(isolated_name),
|
203
|
-
(total_parts_count == real_parts.count)
|
204
|
-
].all?
|
205
|
-
end
|
206
|
-
real_name ? real_name : isolated_name
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def get_real_module(type)
|
211
|
-
if type == :extended_modules
|
212
|
-
active_record_model.singleton_class.included_modules
|
213
|
-
else
|
214
|
-
active_record_model.included_modules
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
def reject_local_const(source)
|
219
|
-
source.reject do |n|
|
220
|
-
class_introspector.locally_defined_constants.values.include?(n)
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
module Attributes
|
226
|
-
def attributes
|
227
|
-
@attributes ||= begin
|
228
|
-
a = schema_scrapper.attributes.to_a
|
229
|
-
a << primary_key unless a.any? { |aa| aa.name == "id" }
|
230
|
-
a.map(&method(:process_attr))
|
231
|
-
a
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
def process_attr(attr)
|
236
|
-
enums = enums(attr.name)
|
237
|
-
attr.default = Virtus::Attribute.build(attr.type).coerce(attr.default)
|
238
|
-
attr.attribute_writer = "write_attribute(:#{attr.name}, val)"
|
239
|
-
attr.attribute_reader = "read_attribute(:#{attr.name})"
|
240
|
-
|
241
|
-
unless enums.empty?
|
242
|
-
enum_type = ActiveMocker::AttributeTypes::Enum.build(
|
243
|
-
enums: enums,
|
244
|
-
table_name: table_name,
|
245
|
-
attribute: attr.name,
|
246
|
-
db_value_type: attr.type,
|
247
|
-
)
|
248
|
-
if ActiveRecord::VERSION::MAJOR == 5
|
249
|
-
enum_type.ignore_value = true
|
250
|
-
attr.type = enum_type
|
251
|
-
if attr.default
|
252
|
-
attr.default = Virtus::Attribute.build(enum_type).get_key(attr.default)
|
253
|
-
end
|
254
|
-
elsif ActiveRecord::VERSION::MAJOR == 4
|
255
|
-
attr.attribute_writer = "@#{attr.name}_enum_type ||= Virtus::Attribute.build(#{enum_type})\nwrite_attribute(:#{attr.name}, @#{attr.name}_enum_type.coerce(val))"
|
256
|
-
attr.attribute_reader = "@#{attr.name}_enum_type ||= Virtus::Attribute.build(#{enum_type})\n@#{attr.name}_enum_type.get_key(read_attribute(:#{attr.name}))"
|
257
|
-
if attr.default
|
258
|
-
attr.default = Virtus::Attribute.build(attr.type).coerce(attr.default)
|
259
|
-
end
|
260
|
-
end
|
261
|
-
attr
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
def enums(attribute)
|
266
|
-
@enums ||= begin
|
267
|
-
raw_enums = class_introspector
|
268
|
-
.class_macros
|
269
|
-
.select { |hash| hash.key?(:enum) }
|
270
|
-
if raw_enums
|
271
|
-
raw_enums
|
272
|
-
.map { |hash| hash[:enum].flatten.first }
|
273
|
-
.each_with_object({}) { |v, h| h.merge!(v) }
|
274
|
-
else
|
275
|
-
{}
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
@enums.fetch(attribute.to_sym, {})
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
module ClassMethods
|
284
|
-
include Attributes
|
285
|
-
|
286
|
-
def attributes_with_defaults
|
287
|
-
types_hash
|
288
|
-
attributes.each_with_object({}) do |attr, hash|
|
289
|
-
hash[attr.name] = attr.default
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
def types_hash
|
294
|
-
@types_hash ||= attributes.each_with_object(HashNewStyle.new) do |attr, types|
|
295
|
-
types[attr.name] = attr.type.to_s
|
296
|
-
end.inspect
|
297
|
-
end
|
298
|
-
|
299
|
-
def associations
|
300
|
-
@associations ||= schema_scrapper.associations.to_a.each_with_object({}) do |a, h|
|
301
|
-
h[a.name] = nil
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
def associations_by_class
|
306
|
-
schema_scrapper.associations.to_a.each_with_object({}) do |r, hash|
|
307
|
-
hash[r.class_name.to_s] ||= {}
|
308
|
-
hash[r.class_name.to_s][r.type] ||= []
|
309
|
-
hash[r.class_name.to_s][r.type] << r.name
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
|
-
def attribute_names
|
314
|
-
attributes.map(&:name)
|
315
|
-
end
|
316
|
-
|
317
|
-
def abstract_class
|
318
|
-
schema_scrapper.abstract_class?
|
319
|
-
end
|
320
|
-
|
321
|
-
def table_name
|
322
|
-
schema_scrapper.table_name
|
323
|
-
end
|
324
|
-
|
325
|
-
def mocked_class
|
326
|
-
[nested_modules, class_name].compact.reject(&:empty?).join("::")
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
Method = Struct.new(:name, :arguments, :body)
|
331
|
-
|
332
|
-
module Scopes
|
333
|
-
def scope_methods
|
334
|
-
class_introspector.class_macros.select { |h| h.keys.first == :scope }.map do |h|
|
335
|
-
a = h.values.first.first
|
336
|
-
Method.new(a[0], ReverseParameters.new(a[1], blocks_as_values: true), nil)
|
337
|
-
end
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
AliasAttributeMethod = Struct.new(:new_name, :old_name)
|
342
|
-
module RecreateClassMethodCalls
|
343
|
-
def class_method_calls
|
344
|
-
@class_method_calls ||= class_introspector
|
345
|
-
.class_macros
|
346
|
-
.select { |h| h.keys.first == :alias_attribute }
|
347
|
-
.map do |h|
|
348
|
-
a = h.values.first.first
|
349
|
-
AliasAttributeMethod.new(a[0].to_s, a[1].to_s)
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
def attribute_aliases
|
354
|
-
class_method_calls.each_with_object({}) do |alias_attr, hash|
|
355
|
-
hash[alias_attr.new_name] = alias_attr.old_name
|
356
|
-
end
|
357
|
-
end
|
358
|
-
end
|
359
|
-
|
360
|
-
module DefinedMethods
|
361
|
-
def instance_methods
|
362
|
-
meths = class_introspector.get_class.public_instance_methods(false).sort
|
363
|
-
if safe_methods.include?(:initialize)
|
364
|
-
meths << :initialize
|
365
|
-
end
|
366
|
-
meths.map { |m| create_method(m, :instance_method) }
|
367
|
-
end
|
368
|
-
|
369
|
-
def class_methods
|
370
|
-
class_introspector
|
371
|
-
.get_class
|
372
|
-
.methods(false)
|
373
|
-
.sort
|
374
|
-
.map { |m| create_method(m, :method) }
|
375
|
-
end
|
376
|
-
|
377
|
-
private
|
378
|
-
|
379
|
-
def safe_methods
|
380
|
-
@safe_methods ||= class_introspector.parsed_source.comments.flat_map do |comment|
|
381
|
-
if comment.text.include?("ActiveMocker.safe_methods")
|
382
|
-
ActiveMocker.module_eval(comment.text.delete("#"))
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
|
-
|
387
|
-
module ActiveMocker
|
388
|
-
def self.safe_methods(*methods)
|
389
|
-
methods
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
def create_method(m, type)
|
394
|
-
if safe_methods.include?(m)
|
395
|
-
def_method = class_introspector.parsed_source.defs.detect { |meth| meth.name == m }
|
396
|
-
Method.new(
|
397
|
-
m,
|
398
|
-
def_method.arguments,
|
399
|
-
def_method.body
|
400
|
-
)
|
401
|
-
else
|
402
|
-
Method.new(
|
403
|
-
m,
|
404
|
-
ReverseParameters.new(
|
405
|
-
class_introspector.get_class.send(type, m).parameters,
|
406
|
-
blocks_as_values: true
|
407
|
-
).parameters,
|
408
|
-
"call_mock_method(method: __method__, caller: Kernel.caller, arguments: [])"
|
409
|
-
)
|
410
|
-
end
|
411
|
-
end
|
412
|
-
end
|
413
|
-
|
414
|
-
module Associations
|
415
|
-
def has_many
|
416
|
-
relation_find(:type, __method__)
|
417
|
-
end
|
418
|
-
|
419
|
-
def has_one
|
420
|
-
relation_find(:type, __method__)
|
421
|
-
end
|
422
|
-
|
423
|
-
def belongs_to
|
424
|
-
relation_find(:type, __method__)
|
425
|
-
end
|
426
|
-
|
427
|
-
def has_and_belongs_to_many
|
428
|
-
relation_find(:type, __method__)
|
429
|
-
end
|
430
|
-
|
431
|
-
def relation_find(key, value)
|
432
|
-
association_collection.select { |r| r.send(key).to_sym == value }
|
433
|
-
end
|
434
|
-
|
435
|
-
def association_collection
|
436
|
-
@association_collection ||= schema_scrapper.associations.to_a
|
437
|
-
end
|
438
|
-
end
|
439
149
|
end
|
440
150
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ActiveMocker
|
3
|
+
class MockCreator
|
4
|
+
module Associations
|
5
|
+
def has_many
|
6
|
+
relation_find(:type, __method__)
|
7
|
+
end
|
8
|
+
|
9
|
+
def has_one
|
10
|
+
relation_find(:type, __method__)
|
11
|
+
end
|
12
|
+
|
13
|
+
def belongs_to
|
14
|
+
relation_find(:type, __method__)
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_and_belongs_to_many
|
18
|
+
relation_find(:type, __method__)
|
19
|
+
end
|
20
|
+
|
21
|
+
def relation_find(key, value)
|
22
|
+
association_collection.select { |r| r.send(key).to_sym == value }
|
23
|
+
end
|
24
|
+
|
25
|
+
def association_collection
|
26
|
+
@association_collection ||= schema_scrapper.associations.to_a
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ActiveMocker
|
3
|
+
class MockCreator
|
4
|
+
module Attributes
|
5
|
+
def attributes
|
6
|
+
@attributes ||= begin
|
7
|
+
a = schema_scrapper.attributes.to_a
|
8
|
+
a << primary_key unless a.any? { |aa| aa.name == "id" }
|
9
|
+
a.map(&method(:process_attr))
|
10
|
+
a
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_attr(attr)
|
15
|
+
enums = enums(attr.name)
|
16
|
+
attr.default = Virtus::Attribute.build(attr.type).coerce(attr.default)
|
17
|
+
attr.attribute_writer = "write_attribute(:#{attr.name}, val)"
|
18
|
+
attr.attribute_reader = "read_attribute(:#{attr.name})"
|
19
|
+
|
20
|
+
unless enums.empty?
|
21
|
+
enum_type = ActiveMocker::AttributeTypes::Enum.build(
|
22
|
+
enums: enums,
|
23
|
+
table_name: table_name,
|
24
|
+
attribute: attr.name,
|
25
|
+
db_value_type: attr.type,
|
26
|
+
)
|
27
|
+
if ActiveRecord::VERSION::MAJOR == 5
|
28
|
+
enum_type.ignore_value = true
|
29
|
+
attr.type = enum_type
|
30
|
+
if attr.default
|
31
|
+
attr.default = Virtus::Attribute.build(enum_type).get_key(attr.default)
|
32
|
+
end
|
33
|
+
elsif ActiveRecord::VERSION::MAJOR == 4
|
34
|
+
attr.attribute_writer = "@#{attr.name}_enum_type ||= Virtus::Attribute.build(#{enum_type})\nwrite_attribute(:#{attr.name}, @#{attr.name}_enum_type.coerce(val))"
|
35
|
+
attr.attribute_reader = "@#{attr.name}_enum_type ||= Virtus::Attribute.build(#{enum_type})\n@#{attr.name}_enum_type.get_key(read_attribute(:#{attr.name}))"
|
36
|
+
if attr.default
|
37
|
+
attr.default = Virtus::Attribute.build(attr.type).coerce(attr.default)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
attr
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def enums(attribute)
|
45
|
+
@enums ||= begin
|
46
|
+
raw_enums = class_introspector
|
47
|
+
.class_macros
|
48
|
+
.select { |hash| hash.key?(:enum) }
|
49
|
+
if raw_enums
|
50
|
+
raw_enums
|
51
|
+
.map { |hash| hash[:enum].flatten.first }
|
52
|
+
.each_with_object({}) { |v, h| h.merge!(v) }
|
53
|
+
else
|
54
|
+
{}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
@enums.fetch(attribute.to_sym, {})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "attributes"
|
3
|
+
|
4
|
+
module ActiveMocker
|
5
|
+
class MockCreator
|
6
|
+
module ClassMethods
|
7
|
+
include Attributes
|
8
|
+
|
9
|
+
def attributes_with_defaults
|
10
|
+
types_hash
|
11
|
+
attributes.each_with_object({}) do |attr, hash|
|
12
|
+
hash[attr.name] = attr.default
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def types_hash
|
17
|
+
@types_hash ||= attributes.each_with_object(HashNewStyle.new) do |attr, types|
|
18
|
+
types[attr.name] = attr.type.to_s
|
19
|
+
end.inspect
|
20
|
+
end
|
21
|
+
|
22
|
+
def associations
|
23
|
+
@associations ||= schema_scrapper.associations.to_a.each_with_object({}) do |a, h|
|
24
|
+
h[a.name] = nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def associations_by_class
|
29
|
+
schema_scrapper.associations.to_a.each_with_object({}) do |r, hash|
|
30
|
+
hash[r.class_name.to_s] ||= {}
|
31
|
+
hash[r.class_name.to_s][r.type] ||= []
|
32
|
+
hash[r.class_name.to_s][r.type] << r.name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def attribute_names
|
37
|
+
attributes.map(&:name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def abstract_class
|
41
|
+
schema_scrapper.abstract_class?
|
42
|
+
end
|
43
|
+
|
44
|
+
def table_name
|
45
|
+
schema_scrapper.table_name
|
46
|
+
end
|
47
|
+
|
48
|
+
def mocked_class
|
49
|
+
[nested_modules, class_name].compact.reject(&:empty?).join("::")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ActiveMocker
|
3
|
+
class MockCreator
|
4
|
+
module DefinedMethods
|
5
|
+
Method = Struct.new(:name, :arguments, :body)
|
6
|
+
|
7
|
+
def instance_methods
|
8
|
+
meths = class_introspector.get_class.public_instance_methods(false).sort
|
9
|
+
if safe_methods.include?(:initialize)
|
10
|
+
meths << :initialize
|
11
|
+
end
|
12
|
+
meths.map { |m| create_method(m, :instance_method) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def class_methods
|
16
|
+
class_introspector
|
17
|
+
.get_class
|
18
|
+
.methods(false)
|
19
|
+
.sort
|
20
|
+
.map { |m| create_method(m, :method) }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def safe_methods
|
26
|
+
@safe_methods ||= class_introspector.parsed_source.comments.flat_map do |comment|
|
27
|
+
if comment.text.include?("ActiveMocker.safe_methods")
|
28
|
+
ActiveMocker.module_eval(comment.text.delete("#"))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ActiveMocker
|
34
|
+
def self.safe_methods(*methods)
|
35
|
+
methods
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_method(m, type)
|
40
|
+
if safe_methods.include?(m)
|
41
|
+
def_method = class_introspector.parsed_source.defs.detect { |meth| meth.name == m }
|
42
|
+
Method.new(
|
43
|
+
m,
|
44
|
+
def_method.arguments,
|
45
|
+
def_method.body
|
46
|
+
)
|
47
|
+
else
|
48
|
+
Method.new(
|
49
|
+
m,
|
50
|
+
ReverseParameters.new(
|
51
|
+
class_introspector.get_class.send(type, m).parameters,
|
52
|
+
blocks_as_values: true
|
53
|
+
).parameters,
|
54
|
+
"call_mock_method(method: __method__, caller: Kernel.caller, arguments: [])"
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ActiveMocker
|
3
|
+
class MockCreator
|
4
|
+
module ModulesConstants
|
5
|
+
class Inspectable
|
6
|
+
attr_reader :inspect
|
7
|
+
|
8
|
+
def initialize(inspect)
|
9
|
+
@inspect = inspect
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def modules
|
14
|
+
@modules ||= begin
|
15
|
+
{
|
16
|
+
included: get_module_by_reference(:included_modules),
|
17
|
+
extended: get_module_by_reference(:extended_modules),
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def constants
|
23
|
+
class_introspector.get_class.constants.each_with_object({}) do |v, const|
|
24
|
+
c = class_introspector.get_class.const_get(v)
|
25
|
+
next if [Module, Class].include?(c.class)
|
26
|
+
if /\A#</ =~ c.inspect
|
27
|
+
const[v] = Inspectable.new("ActiveMocker::UNREPRESENTABLE_CONST_VALUE")
|
28
|
+
else
|
29
|
+
const[v] = c
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def reject_local_const(source)
|
36
|
+
source.reject do |n|
|
37
|
+
class_introspector.locally_defined_constants.values.include?(n)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_real_module(type)
|
42
|
+
if type == :extended_modules
|
43
|
+
active_record_model.singleton_class.included_modules
|
44
|
+
else
|
45
|
+
active_record_model.included_modules
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_module_by_reference(type)
|
50
|
+
isolated_module_names = reject_local_const(class_introspector.public_send(type)).map(&:referenced_name)
|
51
|
+
real_module_names = get_real_module(type).map(&:name).compact
|
52
|
+
isolated_module_names.map do |isolated_name|
|
53
|
+
real_name = real_module_names.detect do |rmn|
|
54
|
+
real_parts = rmn.split("::")
|
55
|
+
total_parts_count = active_record_model.name.split("::").count + isolated_name.split("::").count
|
56
|
+
[
|
57
|
+
real_parts.include?(active_record_model.name),
|
58
|
+
real_parts.include?(isolated_name),
|
59
|
+
(total_parts_count == real_parts.count)
|
60
|
+
].all?
|
61
|
+
end
|
62
|
+
real_name ? real_name : isolated_name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ActiveMocker
|
3
|
+
class MockCreator
|
4
|
+
module RecreateClassMethodCalls
|
5
|
+
AliasAttributeMethod = Struct.new(:new_name, :old_name)
|
6
|
+
|
7
|
+
def class_method_calls
|
8
|
+
@class_method_calls ||= class_introspector
|
9
|
+
.class_macros
|
10
|
+
.select { |h| h.keys.first == :alias_attribute }
|
11
|
+
.map do |h|
|
12
|
+
a = h.values.first.first
|
13
|
+
AliasAttributeMethod.new(a[0].to_s, a[1].to_s)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def attribute_aliases
|
18
|
+
class_method_calls.each_with_object({}) do |alias_attr, hash|
|
19
|
+
hash[alias_attr.new_name] = alias_attr.old_name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module ActiveMocker
|
3
|
+
class MockCreator
|
4
|
+
module Scopes
|
5
|
+
Method = Struct.new(:name, :arguments, :body)
|
6
|
+
|
7
|
+
def scope_methods
|
8
|
+
class_introspector.class_macros.select { |h| h.keys.first == :scope }.map do |h|
|
9
|
+
a = h.values.first.first
|
10
|
+
Method.new(a[0], ReverseParameters.new(a[1], blocks_as_values: true), nil)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
#_class_methods.erb
|
2
2
|
class << self
|
3
|
+
private
|
4
|
+
|
3
5
|
def attributes
|
4
6
|
@attributes ||= HashWithIndifferentAccess.new(<%= attributes_with_defaults.map {|key,value| %Q[#{key}: #{value.inspect}]}.join(", ") %>).merge(super)
|
5
7
|
end
|
@@ -20,7 +22,7 @@
|
|
20
22
|
<%= mocked_class.inspect %>
|
21
23
|
end
|
22
24
|
|
23
|
-
|
25
|
+
public
|
24
26
|
|
25
27
|
def attribute_names
|
26
28
|
@attribute_names ||= attributes.stringify_keys.keys
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# _scopes.erb
|
2
2
|
module Scopes
|
3
|
-
|
3
|
+
include <%= parent_class_inspector.parent_mock_name %>::Scopes
|
4
4
|
|
5
5
|
<% scope_methods.each do |method| -%>
|
6
6
|
def <%= method.name %><%= "(#{method.arguments.parameters})" unless method.arguments.parameters.to_a.empty? %>
|
@@ -9,7 +9,9 @@ RSpec.configure do |config|
|
|
9
9
|
unless ENV["RUN_WITH_RAILS"] && self.class.metadata[:rails_compatible]
|
10
10
|
active_mocker.mocks.each { |class_name, mock| stub_const(class_name, mock) }
|
11
11
|
end
|
12
|
-
|
12
|
+
if (mapping = active_mocker.features[:stub_active_record_exceptions])
|
13
|
+
mapping.each { |class_name, mock| stub_const(class_name, mock) }
|
14
|
+
end
|
13
15
|
end
|
14
16
|
|
15
17
|
config.after(:all, active_mocker: true) do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_mocker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.0
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dustin Zeisler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -227,6 +227,13 @@ files:
|
|
227
227
|
- lib/active_mocker/mock/template_methods.rb
|
228
228
|
- lib/active_mocker/mock/unrepresentable_const_value.rb
|
229
229
|
- lib/active_mocker/mock_creator.rb
|
230
|
+
- lib/active_mocker/mock_creator/associations.rb
|
231
|
+
- lib/active_mocker/mock_creator/attributes.rb
|
232
|
+
- lib/active_mocker/mock_creator/class_methods.rb
|
233
|
+
- lib/active_mocker/mock_creator/defined_methods.rb
|
234
|
+
- lib/active_mocker/mock_creator/modules_constants.rb
|
235
|
+
- lib/active_mocker/mock_creator/recreate_class_method_calls.rb
|
236
|
+
- lib/active_mocker/mock_creator/scopes.rb
|
230
237
|
- lib/active_mocker/mock_template.erb
|
231
238
|
- lib/active_mocker/mock_template/_associations.erb
|
232
239
|
- lib/active_mocker/mock_template/_attributes.erb
|
@@ -260,9 +267,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
260
267
|
version: '2.1'
|
261
268
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
262
269
|
requirements:
|
263
|
-
- - "
|
270
|
+
- - ">="
|
264
271
|
- !ruby/object:Gem::Version
|
265
|
-
version:
|
272
|
+
version: '0'
|
266
273
|
requirements: []
|
267
274
|
rubyforge_project:
|
268
275
|
rubygems_version: 2.5.1
|