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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f21e27c6d5e3d3826ffd754a682e7e35a247cd23
4
- data.tar.gz: 6105da23915b21ac5c3d216ee96ad6e969f1dee4
3
+ metadata.gz: a77d43b16f10346cb55967ea8dcb22e2f0e3474d
4
+ data.tar.gz: d6b4efa5cff2e6a9f3c60ff80120ca9a7b1473d4
5
5
  SHA512:
6
- metadata.gz: bb14e0c20c5ef33a7e55575c0f8b14dfdf42f20d8f07fc0f511993d3819c93b9c202573cade177eac21f7c6ba0c478a93729af388baac83865ec449d22bbc02f
7
- data.tar.gz: d5aca0cb872f5adea5267c8d356b40cffce5bf661cb19d2c7b6f8afd827c54eec941c51c0587c962d013efeeb5b802da81dd12ad1f78d0cdd656ebf453cfe0e1
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
- Enables created_at and updated_at to be update on save and create
203
+
204
+ Enables created_at and updated_at to be update on save and create
203
205
 
204
206
  ### delete_all_before_example
205
- When using "active_mocker/rspec_helper" it delete all records from all mocks before each example.
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.
@@ -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.enabled_partials_default - [*:modules_constants]
101
+ MockCreator::ENABLED_PARTIALS_DEFAULT - [*:modules_constants]
102
102
  else
103
- MockCreator.enabled_partials_default
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
- DEFAULTS = {
9
- timestamps: false,
10
- delete_all_before_example: false,
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)
@@ -6,7 +6,7 @@ module ActiveMocker
6
6
  end
7
7
 
8
8
  module ClassMethods
9
- def transaction
9
+ def transaction(*)
10
10
  yield
11
11
  rescue LocalJumpError => err
12
12
  raise err
@@ -4,6 +4,8 @@ module ActiveMocker
4
4
  end
5
5
  class RecordNotFound < BaseError
6
6
  end
7
+ class RecordNotUnique < BaseError
8
+ end
7
9
 
8
10
  module Mock
9
11
  # @deprecated
@@ -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 || self.class.enabled_partials_default
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
- class << self
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
- public :enabled_partials_default
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
- # -- END defaults -- #
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
- v = ParentClass.new(parsed_source: class_introspector.parsed_source,
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("ActiveMocker::MockCreator::#{p.to_s.camelize}".constantize)
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,6 +1,6 @@
1
1
  require 'active_mocker/mock'
2
2
 
3
- class <%= class_name + mock_append_name %> < <%= parent_class %>
3
+ class <%= class_name + mock_append_name %> < <%= parent_class_inspector.parent_mock_name %>
4
4
 
5
5
  created_with('<%= ActiveMocker::VERSION %>')
6
6
 
@@ -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
- private :mocked_class
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
- include <%= parent_class %>::Scopes
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
- stub_const("ActiveRecord::RecordNotFound", ActiveMocker::RecordNotFound)
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
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ActiveMocker
3
- VERSION = "2.4.0.pre5"
3
+ VERSION = "2.4.0"
4
4
  end
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.pre5
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-10-21 00:00:00.000000000 Z
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: 1.3.1
272
+ version: '0'
266
273
  requirements: []
267
274
  rubyforge_project:
268
275
  rubygems_version: 2.5.1