gorillib 0.1.11 → 0.4.0pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +1 -2
  3. data/.yardopts +9 -0
  4. data/{CHANGELOG.textile → CHANGELOG.md} +35 -9
  5. data/Gemfile +21 -14
  6. data/Guardfile +19 -0
  7. data/{LICENSE.textile → LICENSE.md} +43 -29
  8. data/README.md +47 -52
  9. data/Rakefile +31 -30
  10. data/TODO.md +32 -0
  11. data/VERSION +1 -1
  12. data/examples/builder/ironfan.rb +133 -0
  13. data/examples/model/simple.rb +17 -0
  14. data/gorillib.gemspec +106 -86
  15. data/lib/alt/kernel/call_stack.rb +56 -0
  16. data/lib/gorillib/array/wrap.rb +53 -0
  17. data/lib/gorillib/base.rb +3 -3
  18. data/lib/gorillib/builder/field.rb +5 -0
  19. data/lib/gorillib/builder.rb +260 -0
  20. data/lib/gorillib/collection/has_collection.rb +31 -0
  21. data/lib/gorillib/collection.rb +129 -0
  22. data/lib/gorillib/configurable.rb +28 -0
  23. data/lib/gorillib/datetime/{flat.rb → to_flat.rb} +0 -0
  24. data/lib/gorillib/exception/confidence.rb +17 -0
  25. data/lib/gorillib/exception/raisers.rb +78 -0
  26. data/lib/gorillib/hash/mash.rb +202 -0
  27. data/lib/gorillib/hashlike/slice.rb +53 -19
  28. data/lib/gorillib/hashlike.rb +5 -3
  29. data/lib/gorillib/io/system_helpers.rb +30 -0
  30. data/lib/gorillib/logger/log.rb +18 -0
  31. data/lib/gorillib/metaprogramming/concern.rb +124 -0
  32. data/lib/gorillib/model/active_model_conversion.rb +68 -0
  33. data/lib/gorillib/model/active_model_naming.rb +87 -0
  34. data/lib/gorillib/model/active_model_shim.rb +33 -0
  35. data/lib/gorillib/model/base.rb +341 -0
  36. data/lib/gorillib/model/defaults.rb +71 -0
  37. data/lib/gorillib/model/errors.rb +14 -0
  38. data/lib/gorillib/model/factories.rb +372 -0
  39. data/lib/gorillib/model/field.rb +146 -0
  40. data/lib/gorillib/model/named_schema.rb +53 -0
  41. data/lib/gorillib/{struct/hashlike_iteration.rb → model/overlay.rb} +0 -0
  42. data/lib/gorillib/model/record_schema.rb +9 -0
  43. data/lib/gorillib/model/serialization.rb +23 -0
  44. data/lib/gorillib/model/validate.rb +22 -0
  45. data/lib/gorillib/model.rb +23 -0
  46. data/lib/gorillib/pathname.rb +78 -0
  47. data/lib/gorillib/{serialization.rb → serialization/to_wire.rb} +0 -0
  48. data/lib/gorillib/some.rb +11 -9
  49. data/lib/gorillib/string/constantize.rb +21 -14
  50. data/lib/gorillib/string/inflections.rb +6 -76
  51. data/lib/gorillib/string/inflector.rb +192 -0
  52. data/lib/gorillib/string/simple_inflector.rb +267 -0
  53. data/lib/gorillib/type/extended.rb +52 -0
  54. data/lib/gorillib/utils/capture_output.rb +28 -0
  55. data/lib/gorillib/utils/console.rb +131 -0
  56. data/lib/gorillib/utils/nuke_constants.rb +9 -0
  57. data/lib/gorillib/utils/stub_module.rb +33 -0
  58. data/spec/examples/builder/ironfan_spec.rb +37 -0
  59. data/spec/extlib/hash_spec.rb +64 -0
  60. data/spec/extlib/mash_spec.rb +312 -0
  61. data/spec/{array → gorillib/array}/compact_blank_spec.rb +2 -2
  62. data/spec/{array → gorillib/array}/extract_options_spec.rb +2 -2
  63. data/spec/gorillib/builder_spec.rb +187 -0
  64. data/spec/gorillib/collection_spec.rb +20 -0
  65. data/spec/gorillib/configurable_spec.rb +62 -0
  66. data/spec/{datetime → gorillib/datetime}/parse_spec.rb +3 -3
  67. data/spec/{datetime/flat_spec.rb → gorillib/datetime/to_flat_spec.rb} +4 -4
  68. data/spec/{enumerable → gorillib/enumerable}/sum_spec.rb +5 -5
  69. data/spec/gorillib/exception/raisers_spec.rb +60 -0
  70. data/spec/{hash → gorillib/hash}/compact_spec.rb +2 -2
  71. data/spec/{hash → gorillib/hash}/deep_compact_spec.rb +3 -3
  72. data/spec/{hash → gorillib/hash}/deep_merge_spec.rb +2 -2
  73. data/spec/{hash → gorillib/hash}/keys_spec.rb +2 -2
  74. data/spec/{hash → gorillib/hash}/reverse_merge_spec.rb +2 -2
  75. data/spec/{hash → gorillib/hash}/slice_spec.rb +2 -2
  76. data/spec/{hash → gorillib/hash}/zip_spec.rb +2 -2
  77. data/spec/{hashlike → gorillib/hashlike}/behave_same_as_hash_spec.rb +6 -3
  78. data/spec/{hashlike → gorillib/hashlike}/deep_hash_spec.rb +2 -2
  79. data/spec/{hashlike → gorillib/hashlike}/hashlike_behavior_spec.rb +32 -30
  80. data/spec/{hashlike → gorillib/hashlike}/hashlike_via_accessors_spec.rb +3 -3
  81. data/spec/{hashlike_spec.rb → gorillib/hashlike_spec.rb} +3 -3
  82. data/spec/{logger → gorillib/logger}/log_spec.rb +2 -2
  83. data/spec/{metaprogramming → gorillib/metaprogramming}/aliasing_spec.rb +3 -3
  84. data/spec/{metaprogramming → gorillib/metaprogramming}/class_attribute_spec.rb +3 -3
  85. data/spec/{metaprogramming → gorillib/metaprogramming}/delegation_spec.rb +3 -3
  86. data/spec/{metaprogramming → gorillib/metaprogramming}/singleton_class_spec.rb +3 -3
  87. data/spec/gorillib/model/record/defaults_spec.rb +108 -0
  88. data/spec/gorillib/model/record/factories_spec.rb +321 -0
  89. data/spec/gorillib/model/record/overlay_spec.rb +46 -0
  90. data/spec/gorillib/model/serialization_spec.rb +48 -0
  91. data/spec/gorillib/model_spec.rb +281 -0
  92. data/spec/{numeric → gorillib/numeric}/clamp_spec.rb +2 -2
  93. data/spec/{object → gorillib/object}/blank_spec.rb +2 -2
  94. data/spec/{object → gorillib/object}/try_dup_spec.rb +2 -2
  95. data/spec/{object → gorillib/object}/try_spec.rb +3 -2
  96. data/spec/gorillib/pathname_spec.rb +114 -0
  97. data/spec/{string → gorillib/string}/constantize_spec.rb +2 -2
  98. data/spec/{string → gorillib/string}/human_spec.rb +2 -2
  99. data/spec/{string → gorillib/string}/inflections_spec.rb +4 -3
  100. data/spec/{string → gorillib/string}/inflector_test_cases.rb +0 -0
  101. data/spec/{string → gorillib/string}/truncate_spec.rb +4 -10
  102. data/spec/gorillib/type/extended_spec.rb +120 -0
  103. data/spec/gorillib/utils/capture_output_spec.rb +71 -0
  104. data/spec/spec_helper.rb +8 -11
  105. data/spec/support/gorillib_test_helpers.rb +66 -0
  106. data/spec/support/hashlike_fuzzing_helper.rb +31 -33
  107. data/spec/support/hashlike_helper.rb +3 -3
  108. data/spec/support/model_test_helpers.rb +81 -0
  109. data/spec/support/shared_examples/included_module.rb +20 -0
  110. metadata +177 -158
  111. data/lib/gorillib/array/average.rb +0 -13
  112. data/lib/gorillib/array/sorted_median.rb +0 -11
  113. data/lib/gorillib/array/sorted_percentile.rb +0 -11
  114. data/lib/gorillib/array/sorted_sample.rb +0 -12
  115. data/lib/gorillib/dsl_object.rb +0 -64
  116. data/lib/gorillib/hash/indifferent_access.rb +0 -207
  117. data/lib/gorillib/hash/tree_merge.rb +0 -4
  118. data/lib/gorillib/hashlike/tree_merge.rb +0 -49
  119. data/lib/gorillib/metaprogramming/cattr_accessor.rb +0 -79
  120. data/lib/gorillib/metaprogramming/mattr_accessor.rb +0 -61
  121. data/lib/gorillib/receiver/active_model_shim.rb +0 -32
  122. data/lib/gorillib/receiver/acts_as_hash.rb +0 -195
  123. data/lib/gorillib/receiver/acts_as_loadable.rb +0 -42
  124. data/lib/gorillib/receiver/locale/en.yml +0 -27
  125. data/lib/gorillib/receiver/tree_diff.rb +0 -74
  126. data/lib/gorillib/receiver/validations.rb +0 -30
  127. data/lib/gorillib/receiver.rb +0 -402
  128. data/lib/gorillib/receiver_model.rb +0 -21
  129. data/lib/gorillib/struct/acts_as_hash.rb +0 -108
  130. data/notes/fancy_hashes_and_receivers.textile +0 -120
  131. data/notes/hash_rdocs.textile +0 -97
  132. data/spec/array/average_spec.rb +0 -24
  133. data/spec/array/sorted_median_spec.rb +0 -18
  134. data/spec/array/sorted_percentile_spec.rb +0 -24
  135. data/spec/array/sorted_sample_spec.rb +0 -28
  136. data/spec/dsl_object_spec.rb +0 -99
  137. data/spec/hash/indifferent_access_spec.rb +0 -391
  138. data/spec/metaprogramming/cattr_accessor_spec.rb +0 -43
  139. data/spec/metaprogramming/mattr_accessor_spec.rb +0 -45
  140. data/spec/receiver/acts_as_hash_spec.rb +0 -295
  141. data/spec/receiver_spec.rb +0 -551
  142. data/spec/struct/acts_as_hash_fuzz_spec.rb +0 -71
  143. data/spec/struct/acts_as_hash_spec.rb +0 -422
@@ -0,0 +1,260 @@
1
+ require 'gorillib/string/simple_inflector'
2
+ require 'gorillib/model'
3
+
4
+ module Gorillib
5
+ module Builder
6
+ extend Gorillib::Concern
7
+ include Gorillib::Model
8
+
9
+ def initialize(attrs={}, &block)
10
+ receive!(attrs, &block)
11
+ end
12
+
13
+ def receive!(*args, &block)
14
+ super(*args)
15
+ if block_given?
16
+ (block.arity == 1) ? block.call(self) : self.instance_eval(&block)
17
+ end
18
+ self
19
+ end
20
+
21
+ def getset(field, *args, &block)
22
+ ArgumentError.check_arity!(args, 0..1)
23
+ if args.empty?
24
+ read_attribute(field.name)
25
+ else
26
+ write_attribute(field.name, args.first)
27
+ end
28
+ end
29
+
30
+ def getset_member(field, *args, &block)
31
+ ArgumentError.check_arity!(args, 0..1)
32
+ attrs = args.first
33
+ if attrs.is_a?(field.type)
34
+ # actual object: assign it into field
35
+ val = attrs
36
+ write_attribute(field.name, val)
37
+ else
38
+ val = read_attribute(field.name)
39
+ if val.present?
40
+ # existing item: update it with args and block
41
+ val.receive!(*args, &block) if args.present?
42
+ elsif attrs.blank?
43
+ # missing item (read): return nil
44
+ return nil
45
+ else
46
+ # missing item (write): construct item and add to collection
47
+ options = args.extract_options!.merge(:owner => self)
48
+ val = field.type.receive(*args, options, &block)
49
+ write_attribute(field.name, val)
50
+ end
51
+ end
52
+ val
53
+ end
54
+
55
+ def getset_collection_item(field, item_key, attrs={}, &block)
56
+ plural_name = field.plural_name
57
+ if attrs.is_a?(field.item_type)
58
+ # actual object: assign it into collection
59
+ val = attrs
60
+ set_collection_item(plural_name, item_key, val)
61
+ elsif has_collection_item?(plural_name, item_key)
62
+ # existing item: retrieve it, updating as directed
63
+ val = get_collection_item(plural_name, item_key)
64
+ val.receive!(attrs, &block)
65
+ else
66
+ # missing item: autovivify item and add to collection
67
+ val = field.item_type.receive({ key_method => item_key, :owner => self }.merge(attrs), &block)
68
+ set_collection_item(plural_name, item_key, val)
69
+ end
70
+ val
71
+ end
72
+
73
+ def get_collection_item(plural_name, item_key)
74
+ collection_of(plural_name)[item_key]
75
+ end
76
+
77
+ def set_collection_item(plural_name, item_key, item)
78
+ collection_of(plural_name)[item_key] = item
79
+ end
80
+
81
+ def has_collection_item?(plural_name, item_key)
82
+ collection_of(plural_name).include?(item_key)
83
+ end
84
+
85
+ def key_method
86
+ :name
87
+ end
88
+
89
+ def to_key
90
+ self.read_attribute(key_method)
91
+ end
92
+
93
+ def inspect_helper(detailed, attrs)
94
+ attrs.delete(:owner)
95
+ # detailed ? str : ([str[0..-2], " #{to_key}>"].join)
96
+ str = super(detailed, attrs)
97
+ end
98
+
99
+ def collection_of(plural_name)
100
+ self.read_attribute(plural_name)
101
+ end
102
+
103
+ module ClassMethods
104
+ include Gorillib::Model::ClassMethods
105
+
106
+ def field(field_name, type, options={})
107
+ super(field_name, type, {:field_type => ::Gorillib::Builder::GetsetField}.merge(options))
108
+ end
109
+ def member(field_name, type, options={})
110
+ field(field_name, type, {:field_type => ::Gorillib::Builder::MemberField}.merge(options))
111
+ end
112
+ def collection(field_name, item_type, options={})
113
+ field(field_name, Gorillib::Collection, {
114
+ :item_type => item_type,
115
+ :field_type => ::Gorillib::Builder::CollectionField}.merge(options))
116
+ end
117
+ def simple_field(field_name, type, options={})
118
+ field(field_name, type, {:field_type => ::Gorillib::Model::Field}.merge(options))
119
+ end
120
+
121
+ protected
122
+
123
+ def define_attribute_getset(field)
124
+ field_name = field.name; type = field.type
125
+ define_meta_module_method(field_name, field.visibility(:reader)) do |*args, &block|
126
+ begin
127
+ getset(field, *args, &block)
128
+ rescue StandardError => err ; err.polish("#{self.class}.#{field_name} type #{type} on #{args}'") rescue nil ; raise ; end
129
+ end
130
+ end
131
+
132
+ def define_member_getset(field)
133
+ field_name = field.name; type = field.type
134
+ define_meta_module_method(field_name, field.visibility(:reader)) do |*args, &block|
135
+ begin
136
+ getset_member(field, *args, &block)
137
+ rescue StandardError => err ; err.polish("#{self.class}.#{field_name} type #{type} on #{args}'") rescue nil ; raise ; end
138
+ end
139
+ end
140
+
141
+ def define_collection_getset(field)
142
+ field_name = field.name; item_type = field.item_type
143
+ define_meta_module_method(field.singular_name, field.visibility(:collection_getset)) do |*args, &block|
144
+ begin
145
+ getset_collection_item(field, *args, &block)
146
+ rescue StandardError => err ; err.polish("#{self.class}.#{field_name} c[#{item_type}] on #{args}'") rescue nil ; raise ; end
147
+ end
148
+ end
149
+
150
+ def define_collection_receiver(field)
151
+ plural_name = field.name; item_type = field.item_type; field_type = field.type
152
+ define_meta_module_method("receive_#{plural_name}", true) do |coll, &block|
153
+ begin
154
+ if coll.is_a?(field_type)
155
+ write_attribute(plural_name, coll)
156
+ else
157
+ read_attribute(plural_name).receive!(coll, &block)
158
+ end
159
+ self
160
+ rescue StandardError => err ; err.polish("#{self.class} #{plural_name} c[#{item_type}] on #{args}'") rescue nil ; raise ; end
161
+ end
162
+ end
163
+
164
+ def define_collection_tester(field)
165
+ plural_name = field.plural_name
166
+ define_meta_module_method("has_#{field.singular_name}?", field.visibility(:collection_tester)) do |item_key|
167
+ begin
168
+ collection_of(plural_name).include?(item_key)
169
+ rescue StandardError => err ; err.polish("#{self.class}.#{plural_name} having #{item_key}?'") rescue nil ; raise ; end
170
+ end
171
+ end
172
+
173
+ end
174
+ end
175
+
176
+ module FancyBuilder
177
+ extend Gorillib::Concern
178
+ include Gorillib::Builder
179
+
180
+ included do |base|
181
+ base.field :name, Symbol
182
+ end
183
+
184
+ module ClassMethods
185
+ include Gorillib::Builder::ClassMethods
186
+
187
+ def belongs_to(field_name, type, options={})
188
+ field = field(field_name, type, {:field_type => ::Gorillib::Builder::MemberField }.merge(options))
189
+ define_meta_module_method "#{field.name}_name" do
190
+ val = getset_member(field) or return nil
191
+ val.name
192
+ end
193
+ field
194
+ end
195
+
196
+ def option(field_name, options={})
197
+ type = options.delete(:type){ Whatever }
198
+ field(field_name, type, {:field_type => ::Gorillib::Builder::GetsetField }.merge(options))
199
+ end
200
+
201
+ def collects(type, clxn_name)
202
+ type_handle = type.handle
203
+ define_meta_module_method type_handle do |item_name, attrs={}, options={}, &block|
204
+ send(clxn_name, item_name, attrs, options.merge(:factory => type), &block)
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ module Builder
211
+
212
+ class GetsetField < Gorillib::Model::Field
213
+ self.visibilities = visibilities.merge(:writer => false, :tester => false, :getset => true)
214
+ def inscribe_methods(model)
215
+ model.__send__(:define_attribute_getset, self)
216
+ model.__send__(:define_attribute_writer, self.name, self.type, visibility(:writer))
217
+ model.__send__(:define_attribute_tester, self.name, self.type, visibility(:tester))
218
+ model.__send__(:define_attribute_receiver, self.name, self.type, visibility(:receiver))
219
+ end
220
+ end
221
+
222
+ class MemberField < Gorillib::Model::Field
223
+ self.visibilities = visibilities.merge(:writer => false, :tester => true)
224
+ def inscribe_methods(model)
225
+ model.__send__(:define_member_getset, self)
226
+ model.__send__(:define_attribute_writer, self.name, self.type, visibility(:writer))
227
+ model.__send__(:define_attribute_tester, self.name, self.type, visibility(:tester))
228
+ model.__send__(:define_attribute_receiver, self.name, self.type, visibility(:receiver))
229
+ end
230
+ end
231
+
232
+ class CollectionField < Gorillib::Model::Field
233
+ field :singular_name, Symbol, :default => ->{ Gorillib::Inflector.singularize(name.to_s).to_sym }
234
+ field :item_type, Class, :default => Whatever
235
+
236
+ self.visibilities = visibilities.merge(:writer => false, :tester => false,
237
+ :collection_getset => :public, :collection_tester => true)
238
+
239
+ alias_method :plural_name, :name
240
+ def singular_name
241
+ @singular_name ||= Gorillib::Inflector.singularize(name.to_s).to_sym
242
+ end
243
+
244
+ def inscribe_methods(model)
245
+ item_type = self.item_type
246
+ self.default = ->{ Gorillib::Collection.new(item_type) }
247
+ raise "Plural and singular names must differ: #{self.plural_name}" if (singular_name == plural_name)
248
+ #
249
+ @visibilities[:writer] = false
250
+ model.__send__(:define_attribute_reader, self.name, self.type, visibility(:reader))
251
+ model.__send__(:define_attribute_tester, self.name, self.type, visibility(:tester))
252
+ #
253
+ model.__send__(:define_collection_receiver, self)
254
+ model.__send__(:define_collection_getset, self)
255
+ model.__send__(:define_collection_tester, self)
256
+ end
257
+ end
258
+
259
+ end
260
+ end
@@ -0,0 +1,31 @@
1
+ module Gorillib
2
+ class Collection
3
+ module HasCollection
4
+
5
+ def has_collection(clxn_name, type, key_method=:name)
6
+ plural_name = clxn_name
7
+ singular_name = Gorillib::Inflector.singularize(clxn_name.to_s).to_sym
8
+
9
+ instance_variable_set("@#{plural_name}", Gorillib::Collection.new(type, key_method))
10
+
11
+ define_singleton_method(plural_name) do
12
+ instance_variable_get("@#{plural_name}") if instance_variable_defined?("@#{plural_name}")
13
+ end
14
+
15
+ define_singleton_method(singular_name) do |item_key, attrs={}, options={}, &block|
16
+ collection = instance_variable_get("@#{clxn_name}")
17
+ val = collection.fetch(item_key) do
18
+ attrs.merge!(key_method => item_key, :owner => self) if attrs.respond_to?(:merge!)
19
+ factory = options.fetch(:factory){ type }
20
+ new_val = factory.receive(attrs)
21
+ collection << new_val
22
+ new_val
23
+ end
24
+ val.instance_exec(&block) if block
25
+ val
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,129 @@
1
+ require 'gorillib/metaprogramming/delegation'
2
+ require 'gorillib/metaprogramming/class_attribute'
3
+
4
+ module Gorillib
5
+ class Collection
6
+ # [String, Symbol] Method invoked on a new item to generate its collection key; :to_key by default
7
+ attr_accessor :key_method
8
+ # The default `key_method` invoked on a new item to generate its collection key
9
+ DEFAULT_KEY_METHOD = :to_key
10
+
11
+ # [Class, #receive] Factory for generating a new collection item.
12
+ class_attribute :factory, :instance_writer => false
13
+ singleton_class.class_eval{ protected :factory= }
14
+
15
+ # [{Symbol => Object}] The actual store of items, but not for you to mess with
16
+ attr_reader :clxn
17
+ protected :clxn
18
+
19
+ delegate :[], :[]=, :delete, :fetch, :to => :clxn
20
+ delegate :keys, :values, :each_pair, :each_value, :to => :clxn
21
+ delegate :has_key?, :include?, :length, :size, :empty?, :blank?, :to => :clxn
22
+
23
+ def initialize(factory=nil, key_method=DEFAULT_KEY_METHOD)
24
+ @key_method = key_method
25
+ @factory = factory unless factory.nil?
26
+ @clxn = {}
27
+ end
28
+
29
+ # @return [Array] an array holding the items
30
+ def to_a ; values ; end
31
+ # @return [{Symbol => Object}] a hash of key=>item pairs
32
+ def to_hash ; clxn.dup ; end
33
+
34
+ # Merge the new items in-place; given items clobber existing items
35
+ # @param other [{Symbol => Object}, Array<Object>] a hash of key=>item pairs or a list of items
36
+ # @return [Gorillib::Collection] the collection
37
+ def merge!(other)
38
+ clxn.merge!( convert_collection(other) )
39
+ self
40
+ end
41
+ alias_method :concat, :merge!
42
+ alias_method :receive!, :merge!
43
+
44
+ def self.receive(items, *args)
45
+ coll = new(*args)
46
+ coll.receive!(items)
47
+ coll
48
+ end
49
+
50
+ # Two collections are equal if they have the same class and their contents are equal
51
+ #
52
+ # @param [Gorillib::Collection, Object] other The other collection to compare
53
+ # @return [true, false] True if attributes are equal and other is instance of the same Class
54
+ def ==(other)
55
+ return false unless other.instance_of?(self.class)
56
+ clxn == other.send(:clxn)
57
+ end
58
+
59
+ # Merge the new items into a new collection; given items clobber existing items
60
+ # @param other [{Symbol => Object}, Array<Object>] a hash of key=>item pairs or a list of items
61
+ # @return [Gorillib::Collection] a new merged collection
62
+ def merge(other)
63
+ dup.merge!(other)
64
+ end
65
+
66
+ def create(*args)
67
+ item = factory.receive(*args)
68
+ self << item
69
+ item
70
+ end
71
+
72
+ def find_or_create(key)
73
+ fetch(key){ create(key_method => key) }
74
+ end
75
+
76
+ # Adds an item in-place
77
+ # @return [Gorillib::Collection] the collection
78
+ def <<(val)
79
+ merge! [val]
80
+ self
81
+ end
82
+
83
+ # @return [String] string describing the collection's array representation
84
+ def to_s ; to_a.to_s ; end
85
+ # @return [String] string describing the collection's array representation
86
+ def inspect(detailed=true)
87
+ str = "c{ "
88
+ if detailed
89
+ str << clxn.map do |key, val|
90
+ "%-15s %s" % ["#{key}:", val.inspect]
91
+ end.join(",\n ")
92
+ else
93
+ str << keys.join(", ")
94
+ end
95
+ str << " }"
96
+ end
97
+ # @return [Array] serializable array representation of the collection
98
+ def to_wire(options)
99
+ to_a.map{|el| el.respond_to?(:to_wire) ? el.to_wire(options) : el }
100
+ end
101
+ alias_method(:as_json, :to_wire)
102
+ # @return [String] JSON serialization of the collection's array representation
103
+ def to_json(*args)
104
+ p [self, options]
105
+ to_wire(*args).to_json(*args)
106
+ end
107
+
108
+ protected
109
+
110
+ def convert_value(val)
111
+ return val unless factory
112
+ return nil if val.nil?
113
+ factory.receive(val)
114
+ end
115
+
116
+ # - if the given collection responds_to `to_hash`, it is merged into the internal collection; each hash key *must* match the id of its value or results are undefined.
117
+ # - otherwise, it merges a hash generates from the id/value pairs of each object in the given collection.
118
+ def convert_collection(cc)
119
+ return cc.to_hash if cc.respond_to?(:to_hash)
120
+ cc.inject({}) do |acc, val|
121
+ val = convert_value(val)
122
+ key = val.public_send(key_method).to_sym
123
+ acc[key] = val
124
+ acc
125
+ end
126
+ end
127
+ end
128
+
129
+ end
@@ -0,0 +1,28 @@
1
+ require 'configliere'
2
+ require 'gorillib/builder'
3
+ require 'gorillib/string/inflections'
4
+
5
+ module Gorillib
6
+ module Configurable
7
+ extend Gorillib::Concern
8
+ include Gorillib::Builder
9
+
10
+ module ClassMethods
11
+ def receive(attrs = {}, &blk)
12
+ conf = settings.load_configuration_in_order!(configuration_scope.to_s)
13
+ super(attrs.merge(conf), &blk)
14
+ end
15
+
16
+ def config(name, type, options = {})
17
+ field(name, type, options)
18
+ end
19
+ end
20
+
21
+ included do
22
+ self.class_attribute(:configuration_scope, :settings)
23
+ self.configuration_scope = self.to_s.underscore.to_sym
24
+ self.settings = Configliere::Param.new.use(:commandline, :config_file)
25
+ end
26
+
27
+ end
28
+ end
File without changes
@@ -0,0 +1,17 @@
1
+ module Kernel
2
+ def assert(value, message="Assertion failed", error=StandardError)
3
+ raise error, message, caller unless value
4
+ end
5
+ end
6
+
7
+ class NullObject
8
+ def method_missing(*args, &block)
9
+ self
10
+ end
11
+
12
+ def nil?; true; end
13
+ end
14
+
15
+ def Maybe(value)
16
+ value.nil? ? NullObject.new : value
17
+ end
@@ -0,0 +1,78 @@
1
+ Exception.class_eval do
2
+ # @return [Array] __FILE__, __LINE__, description
3
+ def self.caller_parts
4
+ caller_line = caller[1]
5
+ mg = %r{\A([^:]+):(\d+):in \`([^\']+)\'\z}.match(caller_line) or return [caller_line, 1, 'unknown']
6
+ [mg[1], mg[2].to_i, mg[3]]
7
+ end
8
+
9
+ #
10
+ # @note !! Be sure to rescue the call to this method; few things suck worse than debugging your rescue blocks/
11
+ def polish(extra_info)
12
+ filename, _, method_name = self.class.caller_parts
13
+ method_name.gsub!(/rescue in /, '')
14
+ most_recent_line = backtrace.detect{|line| line.include?(filename) && line.include?(method_name) }
15
+ most_recent_line.sub!(/'$/, " for #{extra_info}'"[0..300])
16
+ end
17
+
18
+ end
19
+
20
+ ArgumentError.class_eval do
21
+ # Raise an error just like Ruby's native message if the array of arguments
22
+ # doesn't match the expected length or range of lengths.
23
+ #
24
+ # @example want `getset(:foo)` to be different from `getset(:foo, nil)`
25
+ # def getset(key, *args)
26
+ # ArgumentError.check_arity!(args, 0..1)
27
+ # return self[key] if args.empty?
28
+ # self[key] = args.first
29
+ # end
30
+ #
31
+ # @overload check_arity!(args, n)
32
+ # @param [Array] args splat args as handed to the caller
33
+ # @param [Integer] val expected length
34
+ # @overload check_arity!(args, x..y)
35
+ # @param [Array] args splat args as handed to the caller
36
+ # @param [#include?] val expected range/list/set of lengths
37
+ # @raise ArgumentError when there are
38
+ def self.check_arity!(args, val)
39
+ allowed_arity = val.is_a?(Integer) ? (val..val) : val
40
+ return true if allowed_arity.include?(args.length)
41
+ raise self.new("wrong number of arguments (#{args.length} for #{val})")
42
+ end
43
+
44
+ # Raise an error just like Ruby's native message if there are fewer arguments
45
+ # than expected
46
+ #
47
+ # @example want to use splat args, requiring at least one
48
+ # def assemble_path(*pathsegs)
49
+ # ArgumentError.arity_at_least!(pathsegs, 1)
50
+ # # ...
51
+ # end
52
+ #
53
+ # @param [Array] args splat args as handed to the caller
54
+ # @param [Integer] val minimum expected length
55
+ def self.arity_at_least!(args, min_arity)
56
+ check_arity!(args, min_arity .. Float::INFINITY)
57
+ end
58
+ end
59
+
60
+ NoMethodError.class_eval do
61
+ MESSAGE = "undefined method `%s' for %s:%s"
62
+
63
+ def self.undefined_method(obj)
64
+ file, line, meth = caller_parts
65
+ self.new(MESSAGE % [meth, obj, obj.class])
66
+ end
67
+
68
+ def self.unimplemented_method(obj)
69
+ file, line, meth = caller_parts
70
+ self.new("#{MESSAGE} -- not implemented yet" % [meth, obj, obj.class])
71
+ end
72
+
73
+ def self.abstract(obj)
74
+ file, line, meth = caller_parts
75
+ self.new("#{MESSAGE} -- must be implemented by the subclass" % [meth, obj, obj.class])
76
+ end
77
+
78
+ end