active_mocker 2.4.0.pre5 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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