naught 2.0.0 → 2.1.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
  SHA256:
3
- metadata.gz: 8e5ec51ba30d9f41f50f07369961f3a1442339734bb90be85b38a0bc839a6465
4
- data.tar.gz: e481b3466ca2ec4c4f48e2cfd37d171f27988d27ec94bb576477ddc3fa6052c0
3
+ metadata.gz: 3e4aa0e2eddca2722a669cb141655ed975ad91535158d9d0cb09566f6971de8f
4
+ data.tar.gz: 2872a770d1b8d58336cee9b29be4b6108511893615c1e2c621ac2e9f8a321e56
5
5
  SHA512:
6
- metadata.gz: 750f5fcec8d8e344cb17023544d16da82b6358fcf9b557766edb403657ad60cd2cdb015f704d3acc4f7d2a4ed44625b2487e9fab83840f1d0e6e4ab57b340d49
7
- data.tar.gz: 3665ffd61394d8ff066aea5702db37eff96d18d49c66783b35d9efd0842860fd6417c6129589c8b349166ebdaa7c144f32a819c0ba7c389a0696049d8a39e4e4
6
+ metadata.gz: c2cf48a809f2777cb2a39c598aac6643bc765b44d39e29c6dbf8c539a394f134f27cced5517f84ca4e7590ec43e0ee01f9b896987c5c48a5b8d08c4793128fad
7
+ data.tar.gz: 8eaa91494482d1a081c1fa6c95b4c54d6e2f5cf6d1cc424bcf86cfd9a09c65618ba5fb46ca7151d2c6d288806aadc578116b97bf85c6f4df14211bf20ce0c5d0
@@ -30,6 +30,14 @@ module Naught
30
30
  # @return [Class] singleton class being mimicked
31
31
  attr_reader :singleton_class
32
32
 
33
+ # The example instance for dynamic method discovery
34
+ # @return [Object, nil] example instance or nil
35
+ attr_reader :example_instance
36
+
37
+ # Whether to include dynamically-defined methods
38
+ # @return [Boolean] whether to include dynamic methods
39
+ attr_reader :include_dynamic
40
+
33
41
  # Create a mimic command for a class or instance
34
42
  #
35
43
  # @param builder [NullClassBuilder]
@@ -60,14 +68,16 @@ module Naught
60
68
  def parse_arguments(class_to_mimic_or_options, options)
61
69
  if class_to_mimic_or_options.is_a?(Hash)
62
70
  options = class_to_mimic_or_options.merge(options)
63
- instance = options.fetch(:example)
64
- @singleton_class = instance.singleton_class
65
- @class_to_mimic = instance.class
71
+ @example_instance = options.fetch(:example)
72
+ @singleton_class = @example_instance.singleton_class
73
+ @class_to_mimic = @example_instance.class
66
74
  else
75
+ @example_instance = nil
67
76
  @singleton_class = NULL_SINGLETON_CLASS
68
77
  @class_to_mimic = class_to_mimic_or_options
69
78
  end
70
79
  @include_super = options.fetch(:include_super, true)
80
+ @include_dynamic = options.fetch(:include_dynamic, !@example_instance.nil?)
71
81
  end
72
82
 
73
83
  # Configure the builder with the mimicked class's properties
@@ -91,8 +101,54 @@ module Naught
91
101
  # @return [Array<Symbol>] methods to stub
92
102
  def methods_to_stub
93
103
  all_methods = class_to_mimic.instance_methods(include_super) | singleton_class.instance_methods(false)
104
+ all_methods |= dynamic_methods if include_dynamic
94
105
  all_methods - METHODS_TO_SKIP
95
106
  end
107
+
108
+ # Discover dynamically-defined methods from the example instance
109
+ #
110
+ # This handles classes like Stripe that use method_missing and
111
+ # respond_to_missing? to define methods based on instance data.
112
+ #
113
+ # @return [Array<Symbol>] dynamic method names
114
+ def dynamic_methods
115
+ return [] unless example_instance
116
+
117
+ candidates = discover_method_candidates
118
+ candidates.select { |name| example_instance.respond_to?(name) }
119
+ end
120
+
121
+ # Discover candidate method names from the example instance
122
+ #
123
+ # Tries multiple approaches to find method names:
124
+ # 1. If the instance responds to :keys (like Stripe objects), use those
125
+ # 2. If the instance responds to :attributes, use those
126
+ # 3. If the instance responds to :to_h or :to_hash, use the hash keys
127
+ #
128
+ # @return [Array<Symbol>] candidate method names
129
+ def discover_method_candidates
130
+ candidates = [] #: Array[Symbol]
131
+
132
+ # Stripe-style objects expose keys
133
+ candidates |= example_instance.keys.map(&:to_sym) if example_instance.respond_to?(:keys)
134
+
135
+ # ActiveRecord-style objects expose attribute_names
136
+ if example_instance.respond_to?(:attribute_names)
137
+ candidates |= example_instance.attribute_names.map(&:to_sym)
138
+ end
139
+
140
+ # OpenStruct-style objects can be converted to hash
141
+ if example_instance.respond_to?(:to_h) && !example_instance.is_a?(Object.const_get(:Hash))
142
+ begin
143
+ hash = example_instance.to_h
144
+ candidates |= hash.keys.map(&:to_sym) if hash.is_a?(Hash)
145
+ rescue
146
+ # Ignore errors from to_h
147
+ end
148
+ end
149
+
150
+ candidates
151
+ end
96
152
  end
97
153
  end
98
154
  end
@@ -1,5 +1,5 @@
1
1
  # Top-level namespace for Naught
2
2
  module Naught
3
3
  # Gem version
4
- VERSION = "2.0.0"
4
+ VERSION = "2.1.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: naught
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Avdi Grimm
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  requirements: []
91
- rubygems_version: 4.0.5
91
+ rubygems_version: 4.0.6
92
92
  specification_version: 4
93
93
  summary: Naught is a toolkit for building Null Objects
94
94
  test_files: []