Neurogami-jimpanzee 1.0.2.1

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.
@@ -0,0 +1,379 @@
1
+ require 'monkeybars/validated_hash'
2
+
3
+ module Monkeybars
4
+ # This is an internal class used only by Monkeybars::View
5
+ #
6
+ # A Mapping records the relationship between the fields of a model or
7
+ # transfer hash and the fields of a view. Mappings are created for each call
8
+ # to View.map. During first usage, the mappings are inspected for validity
9
+ # and are assigned a type (one of the constants defined in Mapping) to speed
10
+ # up processing. Invalid mappings raise an exception.
11
+ class Mapping #:nodoc:
12
+ DIRECTION_TO_VIEW = :to_view
13
+ DIRECTION_FROM_VIEW = :from_view
14
+ DIRECTION_BOTH = :both
15
+ MODEL = :model
16
+ TRANSFER = :transfer
17
+
18
+ class << self
19
+ alias_method :__new__, :new
20
+ end
21
+
22
+ def self.new(mapping_options = {})
23
+ mapping_options.validate_only(:view, :model, :transfer, :using, :ignoring, :translate_using)
24
+ mapping_options.extend HashMappingValidation
25
+
26
+ if mapping_options.properties_only?
27
+ PropertyMapping.__new__(mapping_options)
28
+ elsif mapping_options.methods_only?
29
+ RawMapping.__new__(mapping_options)
30
+ elsif mapping_options.both_properties_and_methods?
31
+ MethodMapping.__new__(mapping_options)
32
+ else
33
+ raise InvalidMappingError, "Cannot determine mapping type with parameters #{mapping_options.inspect}"
34
+ end
35
+ end
36
+
37
+ def initialize(mapping_options = {})
38
+ @view_property = mapping_options[:view] || nil
39
+ @model_property = mapping_options[:model] || nil
40
+ @transfer_property = mapping_options[:transfer] || nil
41
+ @data_translation_hash = mapping_options[:translate_using]
42
+
43
+ @to_view_method, @from_view_method = if mapping_options[:using]
44
+ if mapping_options[:using].kind_of? Array
45
+ [mapping_options[:using][0], mapping_options[:using][1]]
46
+ else
47
+ [mapping_options[:using], nil]
48
+ end
49
+ else
50
+ [nil, nil]
51
+ end
52
+
53
+ @event_types_to_ignore = if mapping_options[:ignoring]
54
+ if mapping_options[:ignoring].kind_of? Array
55
+ mapping_options[:ignoring]
56
+ else
57
+ [mapping_options[:ignoring]]
58
+ end
59
+ else
60
+ []
61
+ end
62
+
63
+ if mapping_options.both_model_and_transfer_present?
64
+ raise InvalidMappingError, "Both model and transfer parameters were given"
65
+ elsif mapping_options.at_least_one_property_present? and !mapping_options.both_properties_present?
66
+ raise InvalidMappingError, "Both a view and a model/transfer property must be provided"
67
+ end
68
+ set_direction(mapping_options)
69
+ end
70
+
71
+ def maps_to_view?
72
+ (DIRECTION_BOTH == @direction) or (DIRECTION_TO_VIEW == @direction)
73
+ end
74
+
75
+ def maps_from_view?
76
+ (DIRECTION_BOTH == @direction) or (DIRECTION_FROM_VIEW == @direction)
77
+ end
78
+
79
+ def to_view(view, model, transfer)
80
+ disable_declared_handlers(view) do
81
+ if model_mapping?
82
+ model_to_view(view, model)
83
+ else
84
+ transfer_to_view(view, transfer) if mapped_transfer_key_present?(transfer)
85
+ end
86
+ end
87
+ end
88
+
89
+ def from_view(view, model, transfer)
90
+ disable_declared_handlers(view) do
91
+ if model_mapping?
92
+ model_from_view(view, model)
93
+ elsif transfer_mapping?
94
+ transfer_from_view(view, transfer)
95
+ end
96
+ end
97
+ end
98
+
99
+ def model_mapping?
100
+ !@model_property.nil?
101
+ end
102
+
103
+ def transfer_mapping?
104
+ !@transfer_property.nil?
105
+ end
106
+
107
+ private
108
+
109
+ def mapped_transfer_key_present?(transfer)
110
+ transfer.has_key? @transfer_property
111
+ end
112
+
113
+ def set_direction(mapping_options)
114
+ @direction = if mapping_options.both_methods_present?
115
+ DIRECTION_BOTH
116
+ elsif mapping_options.to_view_method_present?
117
+ DIRECTION_TO_VIEW
118
+ else
119
+ DIRECTION_FROM_VIEW
120
+ end
121
+ end
122
+
123
+ def disable_declared_handlers(view, &block)
124
+ if @event_types_to_ignore.empty?
125
+ yield
126
+ else
127
+ field = view.get_field_value(/^(\w+)\.?/.match(@view_property)[1])
128
+ @event_types_to_ignore.each do |event_type|
129
+ unless event_type.to_s == "document"
130
+ field.disable_handlers(event_type, &block)
131
+ else
132
+ field.document.disable_handlers(event_type, &block)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ class BasicPropertyMapping < Mapping
140
+ def to_s
141
+ model_or_transfer_key = model_mapping? ? ':model' : ':transfer'
142
+ model_or_transfer_property = model_mapping? ? @model_property : @transfer_property
143
+ ":view => #{@view_property.inspect}, #{model_or_transfer_key} => #{model_or_transfer_property.inspect}"
144
+ end
145
+
146
+ def model_to_view(view, model)
147
+ begin
148
+ instance_eval("view.#{@view_property} = model.#{@model_property}", __FILE__, __LINE__)
149
+ rescue NoMethodError
150
+ raise InvalidMappingError, "Either model.#{@model_property} or self.#{@view_property} in #{view.class} is not valid."
151
+ rescue TypeError => e
152
+ raise InvalidMappingError, "Invalid types when assigning from model.#{@model_property} to self.#{@view_property}, #{e.message} in #{view.class}"
153
+ rescue Monkeybars::UndefinedComponentError
154
+ raise InvalidMappingError, "The view property #{@view_property} was not found on view #{view.class}"
155
+ rescue SyntaxError, Exception => e
156
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
157
+ end
158
+ end
159
+
160
+ def transfer_to_view(view, transfer)
161
+ begin
162
+ instance_eval("view.#{@view_property} = transfer[#{@transfer_property.inspect}]", __FILE__, __LINE__)
163
+ rescue NoMethodError
164
+ raise InvalidMappingError, "Either transfer[#{@transfer_property.inspect}] or self.#{@view_property} in #{view.class} is not valid."
165
+ rescue TypeError => e
166
+ raise InvalidMappingError, "Invalid types when assigning from transfer[#{@transfer_property.inspect}] to self.#{@view_property}, #{e.class}: #{e.message} in #{view.class}"
167
+ rescue SyntaxError, Exception => e
168
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
169
+ end
170
+ end
171
+
172
+ def model_from_view(view, model)
173
+ begin
174
+ instance_eval("model.#{@model_property} = view.#{@view_property}", __FILE__, __LINE__)
175
+ rescue NoMethodError
176
+ raise InvalidMappingError, "Either model.#{@model_property} or self.#{@view_property} in #{view.class} is not valid."
177
+ rescue TypeError => e
178
+ raise InvalidMappingError, "Invalid types when assigning from model.#{@model_property} to self.#{@view_property}, #{e.message} in #{view.class}"
179
+ rescue SyntaxError, Exception => e
180
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
181
+ end
182
+ end
183
+
184
+ def transfer_from_view(view, transfer)
185
+ begin
186
+ instance_eval("transfer[#{@transfer_property.inspect}] = view.#{@view_property}", __FILE__, __LINE__)
187
+ rescue NoMethodError
188
+ raise InvalidMappingError, "Either transfer[#{@transfer_property.inspect}] or self.#{@view_property} in #{view.class} is not valid."
189
+ rescue TypeError => e
190
+ raise InvalidMappingError, "Invalid types when assigning from transfer[#{@transfer_property.inspect}] to self.#{@view_property}, #{e.message} in #{view.class}"
191
+ rescue SyntaxError, Exception => e
192
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
193
+ end
194
+ end
195
+
196
+ private
197
+ def self.new(*args)
198
+ raise "#{self} is not a concrete class"
199
+ end
200
+ end
201
+
202
+ class RawMapping < Mapping
203
+ def to_view(view, model, transfer)
204
+ disable_declared_handlers(view) do
205
+ view.method(@to_view_method).call(model, transfer)
206
+ end
207
+ end
208
+
209
+ def from_view(view, model, transfer)
210
+ view.method(@from_view_method).call(model, transfer) unless @from_view_method.nil?
211
+ end
212
+ end
213
+
214
+ class PropertyMapping < BasicPropertyMapping
215
+ def set_direction(mapping_options)
216
+ @direction = DIRECTION_BOTH
217
+ end
218
+ end
219
+
220
+ class MethodMapping < BasicPropertyMapping
221
+
222
+ def initialize(mapping_properties)
223
+ super
224
+ if using_translation?
225
+ @to_view_translation = @data_translation_hash
226
+ @from_view_translation = @data_translation_hash.invert
227
+ end
228
+ end
229
+
230
+ def to_s
231
+ using_key = using_translation? ? ':using_translation' : ':using'
232
+ using_value = using_translation? ? @data_translation_hash.inspect : "[#{@to_view_method.inspect}, #{@from_view_method.inspect}]"
233
+ super << " #{using_key} => #{using_value}"
234
+ end
235
+
236
+ def using_translation?
237
+ !@data_translation_hash.nil?
238
+ end
239
+
240
+ def model_to_view(view, model)
241
+ if using_translation?
242
+ model_data = instance_eval("model.#{@model_property}", __FILE__, __LINE__)
243
+ unless @to_view_translation.has_key? model_data
244
+ raise TranslationError, "The key #{model_data.inspect} for model #{model.class} does not exist #{@to_view_translation.inspect}"
245
+ end
246
+
247
+ instance_eval("view.#{@view_property} = @to_view_translation[model_data]", __FILE__, __LINE__)
248
+ elsif :default == @to_view_method
249
+ super
250
+ else
251
+ instance_eval("view.#{@view_property} = view.method(@to_view_method).call(model.#{@model_property})", __FILE__, __LINE__)
252
+ end
253
+ rescue NameError => e
254
+ raise InvalidMappingError, "Either view.#{@view_property} or view.#{@to_view_method}(#{@model_property}) is not valid.\nOriginal error: #{e}\n#{e.message}"
255
+ rescue SyntaxError, Exception => e
256
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
257
+ end
258
+
259
+ def transfer_to_view(view, transfer)
260
+ if using_translation?
261
+ transfer_data = instance_eval("transfer[#{@transfer_property.inspect}]", __FILE__, __LINE__)
262
+ unless @to_view_translation.has_key? transfer_data
263
+ raise TranslationError, "The key #{transfer_data.inspect} for transfer does not exist #{@to_view_translation.inspect}"
264
+ end
265
+ instance_eval("view.#{@view_property} = @to_view_translation[transfer_data]", __FILE__, __LINE__)
266
+ elsif :default == @to_view_method
267
+ super
268
+ else
269
+ instance_eval("view.#{@view_property} = view.method(@to_view_method).call(transfer[#{@transfer_property.inspect}])", __FILE__, __LINE__)
270
+ end
271
+ rescue NameError => e
272
+ raise InvalidMappingError, "Either view.#{@view_property} or view.#{@to_view_method}(#{@transfer_property}) is not valid.\nOriginal error: #{e}\n#{e.message}"
273
+ rescue SyntaxError, Exception => e
274
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
275
+ end
276
+
277
+ def model_from_view(view, model)
278
+ if using_translation?
279
+ view_data = instance_eval("view.#{@view_property}", __FILE__, __LINE__)
280
+ unless @from_view_translation.has_key? view_data
281
+ raise TranslationError, "The key #{view_data.inspect} for view #{view.class} does not exist #{@from_view_translation.inspect}"
282
+ end
283
+ instance_eval("model.#{@model_property} = @from_view_translation[view_data]", __FILE__, __LINE__)
284
+ elsif :default == @from_view_method
285
+ super
286
+ else
287
+ instance_eval("model.#{@model_property} = view.method(@from_view_method).call(view.#{@view_property})", __FILE__, __LINE__)
288
+ end
289
+ rescue NameError => e
290
+ raise InvalidMappingError, "Either model.#{@model_property} or view.#{@from_view_method}(#{@view_property}) is not valid.\nOriginal error: #{e}\n#{e.message}"
291
+ rescue SyntaxError, Exception => e
292
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}", e.backtrace
293
+ end
294
+
295
+ def transfer_from_view(view, transfer)
296
+ if using_translation?
297
+ view_data = instance_eval("view.#{@view_property}", __FILE__, __LINE__)
298
+ unless @from_view_translation.has_key? view_data
299
+ raise TranslationError, "The key #{view_data.inspect} for view #{view.class} does not exist #{@from_view_translation.inspect}"
300
+ end
301
+ instance_eval("transfer[#{@transfer_property.inspect}] = @from_view_translation[view_data]", __FILE__, __LINE__)
302
+ elsif :default == @from_view_method
303
+ super
304
+ else
305
+ instance_eval("transfer[#{@transfer_property.inspect}] = view.method(@from_view_method).call(view.#{@view_property})", __FILE__, __LINE__)
306
+ end
307
+ rescue NameError => e
308
+ raise InvalidMappingError, "Either transfer[#{@transfer_property}] or view.#{@from_view_method}(#{@view_property}) is not valid.\nOriginal error: #{e}\n#{e.message}"
309
+ rescue SyntaxError, Exception => e
310
+ raise InvalidMappingError, "Error while trying to map for #{view.class}: #{to_s}\n#{e.class} - #{e}"
311
+ end
312
+ end
313
+
314
+
315
+ module HashMappingValidation
316
+ def properties_only?
317
+ properties = (at_least_one_property_present? and !at_least_one_method_present?)
318
+ (properties and not translate_using_present?) ? true : false
319
+ end
320
+
321
+ def both_properties_and_methods?
322
+ using = (both_properties_present? and at_least_one_method_present?)
323
+ translation = translate_using_present?
324
+ ((using or translation) and not (using and translation)) ? true : false
325
+ end
326
+
327
+ def methods_only?
328
+ (!at_least_one_property_present? and at_least_one_method_present?) ? true : false
329
+ end
330
+
331
+ def translate_using_present?
332
+ !self[:translate_using].nil?
333
+ end
334
+
335
+ def both_properties_present?
336
+ !self[:view].nil? and (!self[:model].nil? or !self[:transfer].nil?)
337
+ end
338
+
339
+ def both_model_and_transfer_present?
340
+ !self[:model].nil? and !self[:transfer].nil?
341
+ end
342
+
343
+ def both_methods_present?
344
+ ((!to_view_method.nil? and !from_view_method.nil?) or translate_using_present?)
345
+ end
346
+
347
+ def to_view_method_present?
348
+ !to_view_method.nil?
349
+ end
350
+
351
+ def from_view_method_present?
352
+ !from_view_method.nil?
353
+ end
354
+
355
+ def at_least_one_property_present?
356
+ !self[:view].nil? or !self[:model].nil? or !self[:transfer].nil?
357
+ end
358
+
359
+ def at_least_one_method_present?
360
+ !to_view_method.nil? or !from_view_method.nil?
361
+ end
362
+
363
+ def to_view_method
364
+ if self[:using].kind_of? Array
365
+ self[:using].first
366
+ else
367
+ self[:using]
368
+ end
369
+ end
370
+
371
+ def from_view_method
372
+ if self[:using].kind_of? Array
373
+ self[:using][1]
374
+ else
375
+ nil
376
+ end
377
+ end
378
+ end
379
+ end
@@ -0,0 +1,114 @@
1
+ module Monkeybars
2
+ class Nesting
3
+ class << self
4
+ alias_method :__new__, :new
5
+ end
6
+
7
+ def self.new(nesting_options = {})
8
+ nesting_options.validate_only(:sub_view, :using, :view)
9
+ nesting_options.extend Monkeybars::HashNestingValidation
10
+
11
+ if nesting_options.property_only?
12
+ PropertyNesting.__new__(nesting_options)
13
+ elsif nesting_options.methods_only?
14
+ MethodNesting.__new__(nesting_options)
15
+ else
16
+ raise InvalidNestingError, "Cannot determine nesting type with parameters #{nesting_options.inspect}"
17
+ end
18
+ end
19
+
20
+ def initialize(properties)
21
+ @sub_view = properties[:sub_view]
22
+ end
23
+ end
24
+
25
+ class PropertyNesting < Nesting
26
+ def initialize(properties)
27
+ super
28
+ @view_property = properties[:view]
29
+ end
30
+
31
+ def nests_with_add?
32
+ true
33
+ end
34
+
35
+ def nests_with_remove?
36
+ true
37
+ end
38
+
39
+ def add(view, nested_view, nested_component, model, transfer)
40
+ instance_eval("view.#{@view_property}.add nested_component")
41
+ end
42
+
43
+ def remove(view, nested_view, nested_component, model, transfer)
44
+ instance_eval("view.#{@view_property}.remove nested_component")
45
+ end
46
+ end
47
+
48
+ class MethodNesting < Nesting
49
+ def initialize(nesting_options)
50
+ super
51
+ @add_method, @remove_method = if nesting_options[:using].kind_of? Array
52
+ [nesting_options[:using][0], nesting_options[:using][1]]
53
+ else
54
+ [nesting_options[:using], nil]
55
+ end
56
+ end
57
+
58
+ def nests_with_add?
59
+ !@add_method.nil?
60
+ end
61
+
62
+ def nests_with_remove?
63
+ !@remove_method.nil?
64
+ end
65
+
66
+ def add(view, nested_view, nested_component, model, transfer)
67
+ #instance_eval("view.#{@add_method}(@sub_view, model, transfer)")
68
+ view.send(@add_method, nested_view, nested_component, model, transfer)
69
+ end
70
+
71
+ def remove(view, nested_view, nested_component, model, transfer)
72
+ #instance_eval("view.#{@remove_method}(@sub_view, model, transfer)")
73
+ view.send(@remove_method, nested_view, nested_component, model, transfer)
74
+ end
75
+ end
76
+
77
+ module HashNestingValidation
78
+ def property_only?
79
+ property_present? and not (to_view_method_present? and from_view_method_present?)
80
+ end
81
+
82
+ def methods_only?
83
+ (to_view_method_present? and from_view_method_present?) and not property_present?
84
+ end
85
+
86
+ def property_present?
87
+ !self[:view].nil?
88
+ end
89
+
90
+ def to_view_method_present?
91
+ !to_view_method.nil?
92
+ end
93
+
94
+ def from_view_method_present?
95
+ !from_view_method.nil?
96
+ end
97
+
98
+ def to_view_method
99
+ if self[:using].kind_of? Array
100
+ self[:using].first
101
+ else
102
+ self[:using]
103
+ end
104
+ end
105
+
106
+ def from_view_method
107
+ if self[:using].kind_of? Array
108
+ self[:using][1]
109
+ else
110
+ nil
111
+ end
112
+ end
113
+ end
114
+ end