gorillib 0.4.1pre → 0.4.2pre
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.
- data/.gitignore +13 -10
- data/.rspec +1 -1
- data/.yardopts +1 -0
- data/CHANGELOG.md +47 -0
- data/Gemfile +22 -19
- data/Guardfile +23 -9
- data/README.md +12 -12
- data/Rakefile +29 -40
- data/VERSION +1 -1
- data/examples/benchmark/factories_benchmark.rb +87 -0
- data/examples/builder/ironfan.rb +1 -19
- data/examples/hash/slicing_methods.rb +101 -0
- data/gorillib.gemspec +36 -35
- data/lib/gorillib/array/deep_compact.rb +4 -3
- data/lib/gorillib/array/simple_statistics.rb +76 -0
- data/lib/gorillib/base.rb +0 -1
- data/lib/gorillib/builder.rb +15 -30
- data/lib/gorillib/collection.rb +159 -57
- data/lib/gorillib/collection/model_collection.rb +136 -43
- data/lib/gorillib/datetime/parse.rb +4 -2
- data/lib/gorillib/{array → deprecated/array}/average.rb +0 -0
- data/lib/gorillib/{array → deprecated/array}/random.rb +2 -1
- data/lib/gorillib/{array → deprecated/array}/sorted_median.rb +0 -0
- data/lib/gorillib/{array → deprecated/array}/sorted_percentile.rb +0 -0
- data/lib/gorillib/deprecated/array/sorted_sample.rb +13 -0
- data/lib/gorillib/{metaprogramming → deprecated/metaprogramming}/aliasing.rb +0 -0
- data/lib/gorillib/enumerable/sum.rb +3 -3
- data/lib/gorillib/exception/raisers.rb +92 -22
- data/lib/gorillib/factories.rb +550 -0
- data/lib/gorillib/hash/mash.rb +15 -58
- data/lib/gorillib/hashlike/deep_compact.rb +2 -2
- data/lib/gorillib/hashlike/slice.rb +55 -40
- data/lib/gorillib/model.rb +5 -3
- data/lib/gorillib/model/base.rb +33 -119
- data/lib/gorillib/model/defaults.rb +58 -14
- data/lib/gorillib/model/errors.rb +10 -0
- data/lib/gorillib/model/factories.rb +1 -367
- data/lib/gorillib/model/field.rb +40 -18
- data/lib/gorillib/model/fixup.rb +16 -0
- data/lib/gorillib/model/positional_fields.rb +35 -0
- data/lib/gorillib/model/schema_magic.rb +162 -0
- data/lib/gorillib/model/serialization.rb +1 -2
- data/lib/gorillib/model/serialization/csv.rb +59 -0
- data/lib/gorillib/pathname.rb +19 -8
- data/lib/gorillib/some.rb +2 -0
- data/lib/gorillib/string/constantize.rb +17 -10
- data/lib/gorillib/string/inflector.rb +11 -7
- data/lib/gorillib/type/boolean.rb +40 -0
- data/lib/gorillib/type/extended.rb +76 -40
- data/lib/gorillib/type/url.rb +6 -4
- data/lib/gorillib/utils/console.rb +1 -18
- data/lib/gorillib/utils/edge_cases.rb +18 -0
- data/spec/examples/builder/ironfan_spec.rb +5 -10
- data/spec/gorillib/array/compact_blank_spec.rb +36 -21
- data/spec/gorillib/array/simple_statistics_spec.rb +143 -0
- data/spec/gorillib/builder_spec.rb +16 -20
- data/spec/gorillib/collection_spec.rb +131 -35
- data/spec/gorillib/exception/raisers_spec.rb +39 -0
- data/spec/gorillib/hash/deep_compact_spec.rb +3 -3
- data/spec/gorillib/model/{record/defaults_spec.rb → defaults_spec.rb} +5 -1
- data/spec/gorillib/model/factories_spec.rb +335 -0
- data/spec/gorillib/model/{record/overlay_spec.rb → overlay_spec.rb} +0 -0
- data/spec/gorillib/model/serialization_spec.rb +2 -2
- data/spec/gorillib/model_spec.rb +19 -18
- data/spec/gorillib/pathname_spec.rb +7 -7
- data/spec/gorillib/string/truncate_spec.rb +3 -13
- data/spec/gorillib/type/extended_spec.rb +50 -2
- data/spec/gorillib/utils/capture_output_spec.rb +1 -1
- data/spec/spec_helper.rb +10 -7
- data/spec/support/factory_test_helpers.rb +76 -0
- data/spec/support/gorillib_test_helpers.rb +36 -24
- data/spec/support/model_test_helpers.rb +39 -2
- metadata +86 -51
- data/lib/alt/kernel/call_stack.rb +0 -56
- data/lib/gorillib/array/sorted_sample.rb +0 -12
- data/lib/gorillib/builder/field.rb +0 -5
- data/lib/gorillib/collection/has_collection.rb +0 -31
- data/lib/gorillib/collection/list_collection.rb +0 -58
- data/lib/gorillib/exception/confidence.rb +0 -17
- data/lib/gorillib/io/system_helpers.rb +0 -30
- data/lib/gorillib/model/record_schema.rb +0 -9
- data/lib/gorillib/utils/stub_module.rb +0 -33
- data/spec/array/average_spec.rb +0 -24
- data/spec/array/sorted_median_spec.rb +0 -18
- data/spec/array/sorted_percentile_spec.rb +0 -24
- data/spec/array/sorted_sample_spec.rb +0 -28
- data/spec/gorillib/metaprogramming/aliasing_spec.rb +0 -180
- data/spec/gorillib/model/record/factories_spec.rb +0 -335
- data/spec/support/kcode_test_helper.rb +0 -16
@@ -9,19 +9,7 @@ module Gorillib
|
|
9
9
|
attribute_set?(:default)
|
10
10
|
end
|
11
11
|
end
|
12
|
-
|
13
|
-
# This is called by `read_attribute` if an attribute is unset; you should
|
14
|
-
# not call this directly. You might use this to provide defaults, or lazy
|
15
|
-
# access, or layered resolution.
|
16
|
-
#
|
17
|
-
# @param [String, Symbol, #to_s] field_name Name of the attribute to unset.
|
18
|
-
# @return [nil] Ze goggles! Zey do nussing!
|
19
|
-
def read_unset_attribute(field_name)
|
20
|
-
field = self.class.fields[field_name]
|
21
|
-
return unless field.has_default?
|
22
|
-
write_attribute(field.name, attribute_default(field))
|
23
|
-
end
|
24
|
-
|
12
|
+
|
25
13
|
# FieldDefaults allows defaults to be declared for your fields
|
26
14
|
#
|
27
15
|
# Defaults are declared by passing the :default option to the field
|
@@ -50,6 +38,60 @@ module Gorillib
|
|
50
38
|
# event.end_date.to_s #=> "2012-01-01"
|
51
39
|
#
|
52
40
|
|
41
|
+
# This is called by `read_attribute` if an attribute is unset; you should
|
42
|
+
# not call this directly. You might use this to provide defaults, or lazy
|
43
|
+
# access, or layered resolution.
|
44
|
+
#
|
45
|
+
# Once a non-nil default value has been read, it is **fixed on the field**; this method
|
46
|
+
# will not be called again, and `attribute_set?(...)` will return `true`.
|
47
|
+
#
|
48
|
+
# @example values are fixed on read
|
49
|
+
# class Defaultable
|
50
|
+
# include Gorillib::Model
|
51
|
+
# field :timestamp, Integer, default: ->{ Time.now }
|
52
|
+
# end
|
53
|
+
# dd = Defaultable.new
|
54
|
+
# dd.attribute_set?(:timestamp) # => false
|
55
|
+
# dd.timestamp # => '2012-01-02 12:34:56 CST'
|
56
|
+
# dd.attribute_set?(:timestamp) # => true
|
57
|
+
# # The block is *not* re-run -- the time is the same
|
58
|
+
# dd.timestamp # => '2012-01-02 12:34:56 CST'
|
59
|
+
#
|
60
|
+
# @example If the default is a literal nil it is set as normal:
|
61
|
+
#
|
62
|
+
# Defaultable.field :might_be_nil, String, default: nil
|
63
|
+
# dd.attribute_set?(:might_be_nil) # => false
|
64
|
+
# dd.might_be_nil # => nil
|
65
|
+
# dd.attribute_set?(:might_be_nil) # => true
|
66
|
+
#
|
67
|
+
# If the default is generated from a block (or anything but a literal nil), no default is set:
|
68
|
+
#
|
69
|
+
# Defaultable.field :might_be_nil, String, default: ->{ puts 'ran!'; some_other_value ? some_other_value.reverse : nil }
|
70
|
+
# Defaultable.field :some_other_value, String
|
71
|
+
# dd = Defaultable.new
|
72
|
+
# dd.attribute_set?(:might_be_nil) # => false
|
73
|
+
# dd.might_be_nil # => nil
|
74
|
+
# 'ran!' # block was run
|
75
|
+
# dd.might_be_nil # => nil
|
76
|
+
# 'ran!' # block was run again
|
77
|
+
# dd.some_other_val = 'hello'
|
78
|
+
# dd.might_be_nil # => 'olleh'
|
79
|
+
# 'ran!' # block was run again, and set a value this time
|
80
|
+
# dd.some_other_val = 'goodbye'
|
81
|
+
# dd.might_be_nil # => 'olleh'
|
82
|
+
# # block was not run again
|
83
|
+
#
|
84
|
+
# @param [String, Symbol, #to_s] field_name Name of the attribute to unset.
|
85
|
+
# @return [Object] The new value
|
86
|
+
def read_unset_attribute(field_name)
|
87
|
+
field = self.class.fields[field_name] or return nil
|
88
|
+
return unless field.has_default?
|
89
|
+
val = attribute_default(field)
|
90
|
+
return nil if val.nil? && (not field.default.nil?) # don't write nil unless intent is clearly to have default nil
|
91
|
+
write_attribute(field.name, val)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
53
95
|
protected
|
54
96
|
|
55
97
|
# the actual default value to assign to the attribute
|
@@ -57,8 +99,10 @@ module Gorillib
|
|
57
99
|
return unless field.has_default?
|
58
100
|
val = field.default
|
59
101
|
case
|
60
|
-
when
|
102
|
+
when val.is_a?(Proc) && (val.arity == 0)
|
61
103
|
self.instance_exec(&val)
|
104
|
+
when val.is_a?(UnboundMethod) && (val.arity == 0)
|
105
|
+
val.bind(self).call
|
62
106
|
when val.respond_to?(:call)
|
63
107
|
val.call(self, field.name)
|
64
108
|
else
|
@@ -10,5 +10,15 @@ module Gorillib
|
|
10
10
|
include Gorillib::Model::Error
|
11
11
|
end
|
12
12
|
|
13
|
+
class ConflictingPositionError < ::ArgumentError
|
14
|
+
include Gorillib::Model::Error
|
15
|
+
end
|
16
|
+
|
17
|
+
# Exception raised if deserialized attributes don't have the right shape:
|
18
|
+
# for example, a CSV line with too many/too few fields
|
19
|
+
class RawDataMismatchError < ::StandardError
|
20
|
+
include Gorillib::Model::Error
|
21
|
+
end
|
22
|
+
|
13
23
|
end
|
14
24
|
end
|
@@ -1,367 +1 @@
|
|
1
|
-
|
2
|
-
require 'gorillib/type/extended'
|
3
|
-
|
4
|
-
def Gorillib::Factory(*args)
|
5
|
-
::Gorillib::Factory.receive(*args)
|
6
|
-
end
|
7
|
-
|
8
|
-
module Gorillib
|
9
|
-
|
10
|
-
module Factory
|
11
|
-
class FactoryMismatchError < ArgumentError ; end
|
12
|
-
|
13
|
-
def self.receive(type)
|
14
|
-
case
|
15
|
-
when factories.include?(type) then return factories[type]
|
16
|
-
when type.respond_to?(:receive) then return type
|
17
|
-
when type.is_a?(Proc) || type.is_a?(Method) then return Gorillib::Factory::ApplyProcFactory.new(type)
|
18
|
-
when type.is_a?(String) then
|
19
|
-
return( factories[type] = Gorillib::Inflector.constantize(Gorillib::Inflector.camelize(type.gsub(/\./, '/'))) )
|
20
|
-
else raise ArgumentError, "Don't know which factory makes a #{type}"
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# Manufactures objects from their raw attributes hash
|
25
|
-
#
|
26
|
-
# A hash with a value for `:_type` is dispatched to the corresponding factory
|
27
|
-
# Everything else is returned directly
|
28
|
-
def self.make(obj)
|
29
|
-
if obj.respond_to?(:has_key?) && (obj.has_key?(:_type) || obj.has_key?('_type'))
|
30
|
-
factory = Gorillib::Factory(attrs[:_type])
|
31
|
-
factory.receive(obj)
|
32
|
-
else
|
33
|
-
obj
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
def self.factories
|
39
|
-
@factories ||= Hash.new
|
40
|
-
end
|
41
|
-
public
|
42
|
-
|
43
|
-
def self.register_factory(factory, typenames)
|
44
|
-
typenames.each{|typename| factories[typename] = factory }
|
45
|
-
end
|
46
|
-
|
47
|
-
class BaseFactory
|
48
|
-
# [Class] The type of objects produced by this factory
|
49
|
-
class_attribute :product
|
50
|
-
|
51
|
-
def initialize(options={})
|
52
|
-
@product = options.delete(:product){ self.class.product }
|
53
|
-
if options[:blankish]
|
54
|
-
define_singleton_method(:blankish, options.delete(:blankish))
|
55
|
-
end
|
56
|
-
redefine(:convert, options.delete(:convert)) if options.has_key?(:convert)
|
57
|
-
warn "Unknown options #{options.keys}" unless options.empty?
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.typename
|
61
|
-
@typename ||= Gorillib::Inflector.underscore(product.name).to_sym
|
62
|
-
end
|
63
|
-
def typename ; self.class.typename ; end
|
64
|
-
|
65
|
-
# A `native` object does not need any transformation; it is accepted directly.
|
66
|
-
# By default, an object is native if it `is_a?(product)`
|
67
|
-
#
|
68
|
-
# @param [Object] obj the object to convert and receive
|
69
|
-
# @return [true, false] true if the item does not need conversion
|
70
|
-
def native?(obj)
|
71
|
-
obj.is_a?(@product)
|
72
|
-
end
|
73
|
-
def self.native?(obj) self.new.native?(obj) ; end
|
74
|
-
|
75
|
-
# A `blankish` object should be converted to `nil`, not a value
|
76
|
-
#
|
77
|
-
# @param [Object] obj the object to convert and receive
|
78
|
-
# @return [true, false] true if the item is equivalent to a nil value
|
79
|
-
def blankish?(obj)
|
80
|
-
obj.nil? || (obj == "")
|
81
|
-
end
|
82
|
-
def self.blankish?(obj)
|
83
|
-
obj.nil? || (obj == "")
|
84
|
-
end
|
85
|
-
|
86
|
-
protected
|
87
|
-
|
88
|
-
def redefine(meth, *args, &block)
|
89
|
-
if args.present?
|
90
|
-
val = args.first
|
91
|
-
case
|
92
|
-
when block_given? then raise ArgumentError, "Pass a block or a value, not both"
|
93
|
-
when val.is_a?(Proc) || val.is_a?(Method) then block = val
|
94
|
-
else block = ->(*){ val.try_dup }
|
95
|
-
end
|
96
|
-
end
|
97
|
-
define_singleton_method(meth, &block)
|
98
|
-
self
|
99
|
-
end
|
100
|
-
|
101
|
-
# Raises a FactoryMismatchError.
|
102
|
-
def mismatched!(obj, message=nil, *args)
|
103
|
-
message ||= "item cannot be converted to #{product}"
|
104
|
-
message << (" got #{obj.inspect}" rescue ' (and is uninspectable)')
|
105
|
-
raise FactoryMismatchError, message, *args
|
106
|
-
end
|
107
|
-
|
108
|
-
def self.register_factory!(*typenames)
|
109
|
-
typenames = [typename, product] if typenames.empty?
|
110
|
-
Gorillib::Factory.register_factory(self.new, typenames)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
class ConvertingFactory < BaseFactory
|
115
|
-
def receive(obj)
|
116
|
-
return nil if blankish?(obj)
|
117
|
-
return obj if native?(obj)
|
118
|
-
convert(obj)
|
119
|
-
rescue NoMethodError, TypeError, RangeError => err
|
120
|
-
mismatched!(obj, err.message, err.backtrace)
|
121
|
-
end
|
122
|
-
protected
|
123
|
-
# Convert a receivable object to the factory's product type. This method
|
124
|
-
# should convert an object to `native?` form or die trying; any
|
125
|
-
# polymorphism (such as converting an empty string to nil) happens in
|
126
|
-
# other methods called by `receive`.
|
127
|
-
#
|
128
|
-
# @param [Object] obj the object to convert.
|
129
|
-
def convert(obj)
|
130
|
-
obj.dup
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
#
|
135
|
-
# A NonConvertingFactory accepts objects that are *already* native, and
|
136
|
-
# throws a mismatch error for anything else.
|
137
|
-
#
|
138
|
-
# @example
|
139
|
-
# ff = Gorillib::Factory::NonConvertingFactory.new(:product => String, :blankish => ->(obj){ obj.nil? })
|
140
|
-
# ff.receive(nil) #=> nil
|
141
|
-
# ff.receive("bob") #=> "bob"
|
142
|
-
# ff.receive(:bob) #=> Gorillib::Factory::FactoryMismatchError: must be an instance of String, got 3
|
143
|
-
#
|
144
|
-
class NonConvertingFactory < BaseFactory
|
145
|
-
def blankish?(obj) obj.nil? ; end
|
146
|
-
def receive(obj)
|
147
|
-
return nil if blankish?(obj)
|
148
|
-
return obj if native?(obj)
|
149
|
-
mismatched!(obj, "must be an instance of #{product},")
|
150
|
-
rescue NoMethodError => err
|
151
|
-
mismatched!(obj, err.message, err.backtrace)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
class ::Whatever < BaseFactory
|
156
|
-
def initialize(options={})
|
157
|
-
options.slice!(:convert, :blankish)
|
158
|
-
super(options)
|
159
|
-
end
|
160
|
-
def native?(obj) true ; end
|
161
|
-
def blankish?(obj) false ; end
|
162
|
-
def receive(obj) obj ; end
|
163
|
-
def self.receive(obj)
|
164
|
-
obj
|
165
|
-
end
|
166
|
-
Gorillib::Factory.register_factory(self, [self, :identical, :whatever])
|
167
|
-
end
|
168
|
-
IdenticalFactory = ::Whatever unless defined?(IdenticalFactory)
|
169
|
-
|
170
|
-
# __________________________________________________________________________
|
171
|
-
#
|
172
|
-
# Concrete Factories
|
173
|
-
# __________________________________________________________________________
|
174
|
-
|
175
|
-
class StringFactory < ConvertingFactory
|
176
|
-
self.product = String
|
177
|
-
def blankish?(obj) obj.nil? ; end
|
178
|
-
def native?(obj) obj.respond_to?(:to_str) end
|
179
|
-
def convert(obj) obj.to_s end
|
180
|
-
register_factory!
|
181
|
-
end
|
182
|
-
|
183
|
-
class GuidFactory < StringFactory ; self.product = ::Guid ; register_factory! ; end
|
184
|
-
class HostnameFactory < StringFactory ; self.product = ::Hostname ; register_factory! ; end
|
185
|
-
class IpAddressFactory < StringFactory ; self.product = ::IpAddress ; register_factory! ; end
|
186
|
-
|
187
|
-
class BinaryFactory < StringFactory
|
188
|
-
def convert(obj)
|
189
|
-
super.force_encoding("BINARY")
|
190
|
-
end
|
191
|
-
register_factory!(:binary)
|
192
|
-
end
|
193
|
-
|
194
|
-
class PathnameFactory < ConvertingFactory
|
195
|
-
self.product = ::Pathname
|
196
|
-
def convert(obj) Pathname.new(obj) end
|
197
|
-
register_factory!
|
198
|
-
end
|
199
|
-
|
200
|
-
class SymbolFactory < ConvertingFactory
|
201
|
-
self.product = Symbol
|
202
|
-
def convert(obj) obj.to_sym end
|
203
|
-
register_factory!
|
204
|
-
end
|
205
|
-
|
206
|
-
class RegexpFactory < ConvertingFactory
|
207
|
-
self.product = Regexp
|
208
|
-
def convert(obj) Regexp.new(obj) end
|
209
|
-
register_factory!
|
210
|
-
end
|
211
|
-
|
212
|
-
class IntegerFactory < ConvertingFactory
|
213
|
-
self.product = Integer
|
214
|
-
def convert(obj) obj.to_i end
|
215
|
-
register_factory!(:int, :integer, Integer)
|
216
|
-
end
|
217
|
-
class BignumFactory < IntegerFactory
|
218
|
-
self.product = Bignum
|
219
|
-
register_factory!
|
220
|
-
end
|
221
|
-
class FloatFactory < ConvertingFactory
|
222
|
-
self.product = Float
|
223
|
-
def convert(obj) obj.to_f end
|
224
|
-
register_factory!
|
225
|
-
end
|
226
|
-
class ComplexFactory < ConvertingFactory
|
227
|
-
self.product = Complex
|
228
|
-
def convert(obj) obj.to_c end
|
229
|
-
register_factory!
|
230
|
-
end
|
231
|
-
class RationalFactory < ConvertingFactory
|
232
|
-
self.product = Rational
|
233
|
-
def convert(obj) obj.to_r end
|
234
|
-
register_factory!
|
235
|
-
end
|
236
|
-
|
237
|
-
class TimeFactory < ConvertingFactory
|
238
|
-
self.product = Time
|
239
|
-
def convert(obj)
|
240
|
-
case obj
|
241
|
-
when String
|
242
|
-
Time.parse(obj).utc
|
243
|
-
when Numeric
|
244
|
-
Time.at(obj).utc
|
245
|
-
end
|
246
|
-
rescue ArgumentError => err
|
247
|
-
warn "Cannot parse time #{obj}: #{err}"
|
248
|
-
return nil
|
249
|
-
end
|
250
|
-
register_factory!
|
251
|
-
end
|
252
|
-
|
253
|
-
# __________________________________________________________________________
|
254
|
-
|
255
|
-
class ClassFactory < NonConvertingFactory ; self.product = Class ; register_factory! ; end
|
256
|
-
class ModuleFactory < NonConvertingFactory ; self.product = Module ; register_factory! ; end
|
257
|
-
class TrueFactory < NonConvertingFactory ; self.product = TrueClass ; register_factory!(:true, TrueClass) ; end
|
258
|
-
class FalseFactory < NonConvertingFactory ; self.product = FalseClass ; register_factory!(:false, FalseClass) ; end
|
259
|
-
|
260
|
-
class ExceptionFactory < NonConvertingFactory ; self.product = Exception ; register_factory!(:exception, Exception) ; end
|
261
|
-
|
262
|
-
class NilFactory < NonConvertingFactory
|
263
|
-
self.product = NilClass
|
264
|
-
def blankish?(obj) false ; end
|
265
|
-
register_factory!(:nil, NilClass)
|
266
|
-
end
|
267
|
-
|
268
|
-
class BooleanFactory < ConvertingFactory
|
269
|
-
self.product = [TrueClass, FalseClass]
|
270
|
-
def blankish?(obj) obj.nil? ; end
|
271
|
-
def native?(obj) obj.equal?(true) || obj.equal?(false) ; end
|
272
|
-
def convert(obj) (obj.to_s == "false") ? false : true ; end
|
273
|
-
register_factory!(:boolean)
|
274
|
-
def self.typename() :boolean ; end
|
275
|
-
end
|
276
|
-
|
277
|
-
#
|
278
|
-
#
|
279
|
-
#
|
280
|
-
|
281
|
-
class EnumerableFactory < ConvertingFactory
|
282
|
-
# [#receive] factory for converting items
|
283
|
-
attr_reader :items_factory
|
284
|
-
|
285
|
-
def initialize(options={})
|
286
|
-
@items_factory = Gorillib::Factory.receive( options.delete(:items){ Gorillib::Factory(:identical) } )
|
287
|
-
redefine(:empty_product, options.delete(:empty_product)) if options.has_key?(:empty_product)
|
288
|
-
super(options)
|
289
|
-
end
|
290
|
-
|
291
|
-
def blankish?(obj) obj.nil? ; end
|
292
|
-
def native?(obj) false ; end
|
293
|
-
|
294
|
-
def empty_product
|
295
|
-
@product.new
|
296
|
-
end
|
297
|
-
|
298
|
-
def convert(obj)
|
299
|
-
clxn = empty_product
|
300
|
-
obj.each do |val|
|
301
|
-
clxn << items_factory.receive(val)
|
302
|
-
end
|
303
|
-
clxn
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
class ArrayFactory < EnumerableFactory
|
308
|
-
self.product = Array
|
309
|
-
register_factory!
|
310
|
-
end
|
311
|
-
|
312
|
-
class SetFactory < EnumerableFactory
|
313
|
-
self.product = Set
|
314
|
-
register_factory!
|
315
|
-
end
|
316
|
-
|
317
|
-
class HashFactory < EnumerableFactory
|
318
|
-
# [#receive] factory for converting keys
|
319
|
-
attr_reader :keys_factory
|
320
|
-
self.product = Hash
|
321
|
-
|
322
|
-
def initialize(options={})
|
323
|
-
@keys_factory = Gorillib::Factory( options.delete(:keys){ Gorillib::Factory(:identical) } )
|
324
|
-
super(options)
|
325
|
-
end
|
326
|
-
|
327
|
-
def convert(obj)
|
328
|
-
hsh = empty_product
|
329
|
-
obj.each_pair do |key, val|
|
330
|
-
hsh[keys_factory.receive(key)] = items_factory.receive(val)
|
331
|
-
end
|
332
|
-
hsh
|
333
|
-
end
|
334
|
-
register_factory!
|
335
|
-
end
|
336
|
-
|
337
|
-
class RangeFactory < NonConvertingFactory
|
338
|
-
self.product = Range
|
339
|
-
def blankish?(obj) obj.nil? || obj == [] ; end
|
340
|
-
register_factory!
|
341
|
-
end
|
342
|
-
|
343
|
-
# __________________________________________________________________________
|
344
|
-
|
345
|
-
class ApplyProcFactory < ConvertingFactory
|
346
|
-
attr_reader :callable
|
347
|
-
|
348
|
-
def initialize(callable=nil, options={}, &block)
|
349
|
-
if block_given?
|
350
|
-
raise ArgumentError, "Pass a block or a value, not both" unless callable.nil?
|
351
|
-
callable = block
|
352
|
-
end
|
353
|
-
@callable = callable
|
354
|
-
super(options)
|
355
|
-
end
|
356
|
-
def blankish?(obj) obj.nil? ; end
|
357
|
-
def native?(val) false ; end
|
358
|
-
def convert(obj)
|
359
|
-
callable.call(obj)
|
360
|
-
end
|
361
|
-
register_factory!(:proc)
|
362
|
-
end
|
363
|
-
|
364
|
-
|
365
|
-
end
|
366
|
-
|
367
|
-
end
|
1
|
+
require_relative '../factories'
|