formize 0.0.2

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,598 @@
1
+ module Formize
2
+
3
+ # Permits to not quote text in inspect method
4
+ class Code < String
5
+
6
+ def inspect
7
+ self.to_s
8
+ end
9
+
10
+ end
11
+
12
+
13
+ class Generator
14
+
15
+ attr_accessor :form, :elements, :record_name, :partial, :controller
16
+
17
+ def initialize(form, controller)
18
+ @form = form
19
+ @controller = controller
20
+ @record_name = @form.record_name
21
+ @elements = form.all_elements
22
+ @partials = @elements.select{|e| !e.depend_on.nil? or e.options[:new]}
23
+ end
24
+
25
+
26
+ # Generates the controller method from a form object
27
+ def controller_code
28
+ code = "def #{form.controller_method_name}\n"
29
+
30
+ # Mono_choice search/filter
31
+ items = form.mono_choices
32
+ if items.size > 0
33
+ code << " if params[:unroll]\n"
34
+ events = form.mono_choices.collect do |mono_choice|
35
+ event = "if params[:unroll] == '#{mono_choice.html_id}'\n"
36
+
37
+ for depended in mono_choice.dependeds
38
+ df = form.fields[depended[:name]]
39
+ event << " #{df.name} = " << (df.reflection.nil? ? "params[:#{df.input_id}]" : "#{df.reflection.class_name}.find_by_id(params[:#{df.input_id}])") << "\n"
40
+ # locals[df.name.to_sym] = Code.new(df.name)
41
+ end
42
+
43
+ event << mono_choice_search_code(mono_choice).strip.gsub(/^/, ' ') << "\n"
44
+ event << "end\n"
45
+ end
46
+ code << events.collect{|e| e.gsub(/^/, ' ')}.join
47
+ code << " end\n"
48
+ end
49
+
50
+ # Dependencies refresh
51
+ items = @partials
52
+ if items.size > 0
53
+ code << " if params[:refresh]\n"
54
+ code << " #{record_name} = #{form.model.name}.find(params[:id]) if params[:id].to_i > 0\n"
55
+ code << " #{record_name} ||= #{form.model.name}.new\n"
56
+ code << " @#{record_name} = #{record_name}\n"
57
+ events = items.collect do |dependent|
58
+ event = "if params[:refresh] == '#{dependent.html_id}'\n"
59
+ locals = {record_name.to_sym => Code.new(record_name)}
60
+ for depended in dependent.dependeds
61
+ df = form.fields[depended[:name]]
62
+ event << " #{record_name}.#{df.name} = " << (df.reflection.nil? ? "params[:#{df.input_id}]" : "#{df.reflection.class_name}.find_by_id(params[:#{df.input_id}])") << "\n"
63
+ # locals[df.name.to_sym] = Code.new(df.name)
64
+ end
65
+ event << " render(:inline=>'<%=#{dependent.prototype}-%>', :locals=>#{locals.inspect})\n"
66
+ event << "end\n"
67
+ end
68
+ code << events.collect{|e| e.gsub(/^/, ' ')}.join
69
+ code << " end\n"
70
+ end
71
+
72
+ # End
73
+ code << "end\n"
74
+ code.gsub!(/end\s*if/, 'elsif')
75
+ # raise code
76
+ list = code.split("\n"); list.each_index{|x| puts((x+1).to_s.rjust(4)+": "+list[x])}
77
+ return code
78
+ end
79
+
80
+
81
+
82
+ # Generates the view method from a form object
83
+ def view_code
84
+ code = ""
85
+
86
+ varh = 'html'
87
+
88
+ # Build view methods assimilated to partials
89
+ for element in @partials
90
+ code << "# #{element.class.name}: #{element.html_id}/#{element.name}\n"
91
+ code << view_method_code(element, varh)
92
+ end
93
+
94
+
95
+ code << "\n"
96
+ code << "def #{form.options[:view_fields_method_name]}(#{form.record_name}=nil)\n"
97
+ code << " #{form.record_name} = @#{form.record_name} unless #{form.record_name}.is_a?(#{form.model.name})\n"
98
+ code << " #{varh} = ''\n"
99
+ for element in form.elements
100
+ code << view_method_call(element, varh).strip.gsub(/^/, ' ') << "\n" #
101
+ # code << " #{varh} << " << element.method_call_code.gsub(/^/, ' ').strip << "\n"
102
+ end
103
+ code << " return #{varh}\n"
104
+ code << "end\n"
105
+
106
+ code << "\n"
107
+ code << "def #{form.options[:view_form_method_name]}(#{form.record_name}=nil)\n"
108
+ code << " #{form.record_name} = @#{form.record_name} unless #{form.record_name}.is_a?(#{form.model.name})\n"
109
+ code << " return form_for(#{form.record_name}) do\n"
110
+ code << " #{form.options[:view_fields_method_name]}(#{form.record_name})\n"
111
+ code << " end\n"
112
+ code << "end\n"
113
+
114
+ # raise code
115
+ list = code.split("\n"); list.each_index{|x| puts((x+1).to_s.rjust(4)+": "+list[x])}
116
+ return code
117
+ end
118
+
119
+
120
+
121
+
122
+
123
+ def view_partial_code(element, varh='varh')
124
+ # send("#{element.class.name.split('::')[-1].underscore}_#{__method__}", element, varh)
125
+ special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
126
+ code = ""
127
+ partial_code = send(special_method, element, varh)
128
+ dependeds = element.dependeds.collect{|d| d[:name]}
129
+ if dependeds.size > 0
130
+ for depended in dependeds
131
+ depended_field = form.fields[depended]
132
+ code << "#{depended_field.name} = #{form.record_name}.#{depended_field.name}\n"
133
+ if depended_field.reflection
134
+ code << "#{depended_field.name} ||= #{field_datasource(depended_field)}.first\n"
135
+ end
136
+ end
137
+
138
+ code << "if #{dependeds.join(' and ')}\n"
139
+
140
+ code << partial_code.strip.gsub(/^/, ' ') << "\n"
141
+
142
+ code << "else\n"
143
+ code << " #{varh} << content_tag(:div, '', #{wrapper_attrs(element).inspect})\n"
144
+ code << "end\n"
145
+ else
146
+ code = partial_code
147
+ end
148
+ return code
149
+ end
150
+
151
+ def view_method_code(element, varh='varh')
152
+ # send("#{element.class.name.split('::')[-1].underscore}_#{__method__}", element, varh)
153
+ special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
154
+ return send(special_method, element, varh) if self.respond_to?(special_method)
155
+ code = "def #{element.prototype}\n"
156
+ code << " #{varh} = ''\n"
157
+ code << view_partial_code(element, varh).strip.gsub(/^/, ' ') << "\n"
158
+ code << " return #{varh}\n"
159
+ code << "end\n"
160
+ return code
161
+ end
162
+
163
+ def view_method_call(element, varh='varh')
164
+ special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
165
+ return send(special_method, element, varh) if self.respond_to?(special_method)
166
+ if @partials.include?(element)
167
+ return "#{varh} << #{element.prototype}\n"
168
+ else
169
+ return view_partial_code(element, varh).strip << "\n"
170
+ end
171
+ end
172
+
173
+ def wrapper_attrs(element)
174
+ html_options = (element.respond_to?(:html_options) ? element.html_options : {})
175
+ html_options[:id] = element.html_id
176
+ if @partials.include?(element)
177
+ url = {:controller => controller.controller_name.to_sym, :action=>form.action_name.to_sym, :refresh=>element.html_id}
178
+ for depended in element.dependeds
179
+ df = form.fields[depended[:name]]
180
+ url[df.input_id.to_sym] = Code.new(df.reflection.nil? ? df.name : "#{df.name}.id")
181
+ end
182
+ html_options["data-refresh"] = Code.new("url_for(#{url.inspect})")
183
+ end
184
+ special_method = "#{element.class.name.split('::')[-1].underscore}_#{__method__}".to_sym
185
+ return send(special_method, element, html_options) if self.respond_to?(special_method)
186
+ return html_options
187
+ end
188
+
189
+ #####################################################################################
190
+ # F I E L D _ S E T M E T H O D S #
191
+ #####################################################################################
192
+
193
+ def field_set_view_partial_code(field_set, varh='varh')
194
+ # Initialize html attributes
195
+ html_options = wrapper_attrs(field_set)
196
+
197
+ varc = field_set.html_id # "field_set_#{field_set.html_id}"
198
+ code = "#{varh} << hard_content_tag(:fieldset, #{html_options.inspect}) do |#{varc}|\n"
199
+ unless field_set.title.nil?
200
+ code << " #{varc} << content_tag(:legend, ::I18n.translate('labels.#{field_set.title}'))\n"
201
+ end
202
+ for child in field_set.children
203
+ code << view_method_call(child, varc).strip.gsub(/^/, ' ') << "\n"
204
+ end
205
+ code << "end\n"
206
+ return code
207
+ end
208
+
209
+ # def field_set_view_method_code(field_set, varh='html')
210
+ # code = "def #{field_set.prototype}\n"
211
+ # code << " #{varh} = ''\n"
212
+ # code << field_set_view_partial_code(field_set, varh).strip.gsub(/^/, ' ') << "\n"
213
+ # code << " return #{varh}\n"
214
+ # code << "end\n"
215
+ # return code
216
+ # end
217
+
218
+ # def field_set_view_method_call(field_set, varh='varh')
219
+ # code = ""
220
+ # call = if @partials.include?(field_set)
221
+ # "#{varh} << #{field_set.prototype}\n"
222
+ # else
223
+ # field_set_view_partial_code(field_set, varh).strip << "\n"
224
+ # end
225
+
226
+ # if field_set.depend_on
227
+ # depended_field = form.fields[field_set.depend_on]
228
+ # code << "#{field_set.depend_on} = #{form.record_name}.#{depended_field.name}\n"
229
+ # if ref = depended_field.reflection
230
+ # code << "#{field_set.depend_on} ||= #{field_datasource(depended_field)}.first\n"
231
+ # end
232
+ # code << "if #{field_set.depend_on}\n"
233
+ # code << call.strip.gsub(/^/, ' ') << "\n"
234
+ # code << "else\n"
235
+ # opt = {:id=>field_set.html_id, :class=>"waiting", "data-refresh"=>Code.new("url_for(:controller=>:#{controller.controller_name}, :action=>:#{form.action_name}, :refresh=>'#{field_set.html_id}')")}
236
+ # code << " #{varh} << tag(:div, #{opt.inspect})\n"
237
+
238
+ # code << "end\n"
239
+ # else
240
+ # code = call
241
+ # end
242
+
243
+ # return code
244
+ # end
245
+
246
+ #####################################################################################
247
+ # F I E L D M E T H O D S #
248
+ #####################################################################################
249
+
250
+ def field_view_partial_code(field, varh='varh')
251
+ input_attrs = (field.options[:input_options].is_a?(Hash) ? field.options[:input_options] : {})
252
+ deps = form.dependents_on(field)
253
+ if deps.size > 0
254
+ input_attrs["data-dependents"] = deps.collect{|d| d.html_id}.join(',')
255
+ end
256
+
257
+ # Initialize html attributes
258
+ html_options = wrapper_attrs(field)
259
+
260
+ varc = field.html_id
261
+ code = "#{varh} << hard_content_tag(:div, #{html_options.inspect}) do |#{varc}|\n"
262
+ code << " #{varc} << label(:#{form.record_name}, :#{field.name}, nil, :class=>'attr')\n"
263
+ code << " #{form.record_name}.#{field.name} ||= #{field.default.inspect}\n" if field.default
264
+ code << self.send("field_#{field.type}_input", field, input_attrs, varc).strip.gsub(/^/, ' ') << "\n"
265
+ code << "end\n"
266
+ return code
267
+ end
268
+
269
+ # def field_view_method_code(field, varh='html')
270
+ # code = "def #{field.prototype}\n"
271
+ # code << " #{varh} = ''\n"
272
+ # code << field_view_partial_code(field, varh).strip.gsub(/^/, ' ') << "\n"
273
+ # code << " return #{varh}\n"
274
+ # code << "end\n"
275
+ # return code
276
+ # end
277
+
278
+ # def field_view_method_call(field, varh='varh')
279
+ # code = ""
280
+ # call = if @partials.include?(field)
281
+ # "#{varh} << #{field.prototype}\n"
282
+ # else
283
+ # field_view_partial_code(field, varh).strip << "\n"
284
+ # end
285
+
286
+ # if field.depend_on
287
+ # depended_field = form.fields[field.depend_on]
288
+ # code << "#{field.depend_on} = #{form.record_name}.#{depended_field.name}\n"
289
+ # code << "if #{field.depend_on}\n"
290
+ # code << call.strip.gsub(/^/, ' ') << "\n"
291
+ # code << "else\n"
292
+ # attrs = field_wrapper_attrs(field)
293
+ # attrs[:class] = "#{attrs[:class]} waiting".strip
294
+ # code << " #{varh} << tag(:div, #{attrs.inspect})\n"
295
+ # code << "end\n"
296
+ # else
297
+ # code = call
298
+ # end
299
+
300
+ # return code
301
+ # end
302
+
303
+
304
+ def field_datasource(field)
305
+ source = field.source
306
+ source = Formize.default_source unless [Array, String, Symbol].include?(source.class)
307
+ if source.is_a?(Array)
308
+ return "#{source[0]}.#{field.choices}"
309
+ elsif source == :foreign_class
310
+ return "#{field.reflection.class_name}.#{field.choices}"
311
+ elsif source == :class
312
+ return "#{form.model.name}.#{field.choices}"
313
+ else
314
+ return "#{source}.#{field.choices}"
315
+ end
316
+ end
317
+
318
+ def field_datasource_class_name(field)
319
+ source = field.source
320
+ source = Formize.default_source unless [Array, String, Symbol].include?(source.class)
321
+ if source.is_a?(Array)
322
+ return source[1]
323
+ elsif source == :foreign_class
324
+ return field.reflection.class_name
325
+ elsif source == :class
326
+ return form.model.name
327
+ else
328
+ return source.to_s.classify
329
+ end
330
+ end
331
+
332
+ def field_input_options(field)
333
+ end
334
+
335
+ def field_wrapper_attrs(field, html_options={})
336
+ html_options[:class] = "field #{html_options[:class]}".strip
337
+ html_options[:class] = "#{html_options[:class]} #{field.type.to_s.gsub('_', '-')}".strip
338
+ html_options[:class] = "#{html_options[:class]} required".strip if field.required
339
+ return html_options
340
+ end
341
+
342
+
343
+
344
+
345
+ def field_check_box_input(field, attrs={}, varc='varc')
346
+ return "#{varc} << check_box(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
347
+ end
348
+
349
+ def field_choice_input(field, attrs={}, varc='varc')
350
+ code = if field.choices.size <= Formize.radio_count_max
351
+ field_radio_input(field, attrs, varc)
352
+ else
353
+ field_select_input(field, attrs, varc)
354
+ end
355
+ return code
356
+ end
357
+
358
+ def field_date_input(field, attrs={}, varc='varc')
359
+ attrs[:size] ||= 16
360
+ return "#{varc} << date_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
361
+ end
362
+
363
+ def field_datetime_input(field, attrs={}, varc='varc')
364
+ attrs[:size] ||= 16
365
+ return "#{varc} << datetime_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
366
+ end
367
+
368
+ def field_label_input(field, attrs={}, varc='varc')
369
+ attrs[:class] = (attrs[:class]+" readonly").strip
370
+ return "#{varc} << content_tag(:span, @:#{field.record_name}.#{field.method}, #{attrs.inspect})\n"
371
+ end
372
+
373
+ def field_numeric_input(field, attrs={}, varc='varc')
374
+ attrs[:size] ||= 16
375
+ return "#{varc} << text_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
376
+ end
377
+
378
+ def field_password_input(field, attrs={}, varc='varc')
379
+ attrs[:size] ||= 24
380
+ return "#{varc} << password_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
381
+ end
382
+
383
+ def field_radio_input(field, attrs={}, varc='varc')
384
+ return "#{varc} << radio(:#{field.record_name}, :#{field.method}, #{field.choices.inspect}, #{attrs.inspect})\n"
385
+ # return "#{varc} << " << field.choices.collect{|x| "content_tag(:span, radio_button(:#{field.record_name}, :#{field.method}, #{x[1].inspect}) << ' ' << content_tag(:label, #{x[0].inspect}, :for=>'#{field.input_id}_#{x[1]}'), :class=>'rad')"}.join(" << ") << "\n"
386
+ end
387
+
388
+ def field_select_input(field, attrs={}, varc='varc')
389
+ if (include_blank = attrs.delete(:include_blank)).is_a? String
390
+ field.choices.insert(0, [include_blank, ''])
391
+ end
392
+ return "#{varc} << select(:#{field.record_name}, :#{field.method}), #{field.choices.inspect}, #{attrs.inspect})\n"
393
+ end
394
+
395
+ def field_mono_choice_input(field, attrs={}, varc='varc')
396
+ source_model = field_datasource_class_name(field).constantize
397
+ reflection = source_model.reflections[field.choices]
398
+ if reflection.nil?
399
+ raise Exception.new("#{source_model.name} must have a reflection :#{field.choices}.")
400
+ end
401
+ count = "#{field.choices}_count"
402
+ select_first_if_empty = " #{record_name}.#{field.name} ||= #{field_datasource(field)}.first\n"
403
+ code = "#{count} = #{field_datasource(field)}.count\n"
404
+ code << "if (#{count} == 0)\n"
405
+ code << field_mono_select_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
406
+ code << "elsif (#{count} <= #{Formize.radio_count_max})\n"
407
+ code << select_first_if_empty
408
+ code << field_mono_radio_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
409
+ if reflection.options[:finder_sql].nil?
410
+ code << "elsif (#{count} <= #{Formize.select_count_max})\n"
411
+ code << select_first_if_empty
412
+ code << field_mono_select_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
413
+ code << "else\n"
414
+ code << select_first_if_empty
415
+ code << field_mono_unroll_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
416
+ else
417
+ code << "else\n"
418
+ code << select_first_if_empty
419
+ code << field_mono_select_input(field, attrs, varc).strip.gsub(/^/, ' ') << "\n"
420
+ end
421
+ code << "end\n"
422
+
423
+ new_item_url = field.options.delete(:new)
424
+ if new_item_url.is_a? Symbol
425
+ new_item_url = {:controller=>new_item_url.to_s.pluralize.to_sym}
426
+ elsif new_item_url.is_a? TrueClass
427
+ new_item_url = {}
428
+ end
429
+
430
+ if new_item_url.is_a?(Hash)
431
+ for k, v in new_item_url
432
+ new_item_url[k] = Code.new(v) if v.is_a?(String)
433
+ end
434
+ edit_item_url = {} unless edit_item_url.is_a? Hash
435
+ if field.method.to_s.match(/_id$/) and refl = form.model.reflections[field.method.to_s[0..-4].to_sym]
436
+ new_item_url[:controller] ||= refl.class_name.underscore.pluralize
437
+ edit_item_url[:controller] ||= new_item_url[:controller]
438
+ end
439
+ new_item_url[:action] ||= :new
440
+ edit_item_url[:action] ||= :edit
441
+ data = field.options.delete(:update)||field.html_id
442
+ html_options = {"data-add-item"=>data, :class=>"icon im-new"}
443
+ code << "#{varc} << content_tag(:span, content_tag(:span, link_to(tg(:new), #{new_item_url.inspect}, #{html_options.inspect}).html_safe, :class=>:tool).html_safe, :class=>\"toolbar mini-toolbar\") if authorized?(#{new_item_url.inspect})\n"
444
+ end
445
+ return code
446
+ end
447
+
448
+ def field_mono_radio_input(field, attrs={}, varc='varc')
449
+ return "#{varc} << radio(:#{field.record_name}, :#{field.method}, #{field_datasource(field)}.collect{|item| [item.#{field.item_label}, item.id]}, {}, #{attrs.inspect})"
450
+ end
451
+
452
+ def field_mono_select_input(field, attrs={}, varc='varc')
453
+ return "#{varc} << select(:#{field.record_name}, :#{field.method}, #{field_datasource(field)}.collect{|item| [item.#{field.item_label}, item.id]}, {}, #{attrs.inspect})"
454
+ end
455
+
456
+ def field_mono_unroll_input(field, attrs={}, varc='varc')
457
+ options = {}
458
+ options[:label] ||= Code.new("Proc.new{|r| \"#{mono_choice_label(field, 'r')}\"}")
459
+ url = {:controller=>controller.controller_name, :action=>form.action_name, :unroll=>field.html_id}
460
+ for depended in field.dependeds
461
+ df = form.fields[depended[:name]]
462
+ url[df.input_id.to_sym] = Code.new(df.reflection.nil? ? df.name : "#{df.name}.id")
463
+ end
464
+ return "#{varc} << unroll(:#{field.record_name}, :#{field.method}, url_for(#{url.inspect}), #{options.inspect}, #{attrs.inspect})"
465
+ end
466
+
467
+ def field_string_input(field, attrs={}, varc='varc')
468
+ attrs[:size] ||= 24
469
+ if field.column and !field.column.limit.nil?
470
+ attrs[:size] = field.column.limit if field.column.limit<attrs[:size]
471
+ attrs[:maxlength] = field.column.limit
472
+ end
473
+ return "#{varc} << text_field(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
474
+ end
475
+
476
+ def field_text_area_input(field, attrs={}, varc='varc')
477
+ attrs[:cols] ||= 40
478
+ attrs[:rows] ||= 3
479
+ attrs[:class] = "#{attrs[:class]} #{attrs[:cols]==80 ? :code : nil}".strip
480
+ return "#{varc} << text_area(:#{field.record_name}, :#{field.method}, #{attrs.inspect})\n"
481
+ end
482
+
483
+
484
+
485
+
486
+
487
+
488
+ protected
489
+
490
+ def sanitize_conditions(value)
491
+ if value.is_a? Array
492
+ if value.size==1 and value[0].is_a? String
493
+ value[0].to_s
494
+ else
495
+ value.inspect
496
+ end
497
+ elsif value.is_a? String
498
+ '"'+value.gsub('"','\"')+'"'
499
+ elsif [Date, DateTime].include? value.class
500
+ '"'+value.to_formatted_s(:db)+'"'
501
+ else
502
+ value.to_s
503
+ end
504
+ end
505
+
506
+
507
+ def mono_choice_label(choice, varr='record')
508
+ return "\#\{#{varr}.#{choice.item_label}\}"
509
+ end
510
+
511
+ def mono_choice_search_code(field)
512
+ source_model = field_datasource_class_name(field).constantize
513
+ reflection = source_model.reflections[field.choices]
514
+ if reflection.nil?
515
+ raise Exception.new("#{source_model.name} must have a reflection :#{field.choices}.")
516
+ end
517
+ model = reflection.class_name.constantize
518
+ foreign_record = model.name.underscore
519
+ foreign_records = "#{source_model.name.underscore}_#{field.choices}"
520
+ options = field.options
521
+ attributes = field.search_attributes
522
+ attributes = [attributes] unless attributes.is_a? Array
523
+ attributes_hash = {}
524
+ attributes.each_index do |i|
525
+ attribute = attributes[i]
526
+ attributes[i] = [
527
+ (attribute.to_s.match(/\./) ? attribute.to_s : model.table_name+'.'+attribute.to_s.split(/\:/)[0]),
528
+ (attribute.to_s.match(/\:/) ? attribute.to_s.split(/\:/)[1] : (options[:filter]||'%X%')),
529
+ '_a'+i.to_s]
530
+ attributes_hash[attributes[i][2]] = attributes[i][0]
531
+ end
532
+ query = []
533
+ parameters = ''
534
+ if options[:conditions].is_a? Hash
535
+ options[:conditions].each do |key, value|
536
+ query << (key.is_a?(Symbol) ? model.table_name+"."+key.to_s : key.to_s)+'=?'
537
+ parameters += ', ' + sanitize_conditions(value)
538
+ end
539
+ elsif options[:conditions].is_a? Array
540
+ conditions = options[:conditions]
541
+ case conditions[0]
542
+ when String # SQL
543
+ # query << '["'+conditions[0].to_s+'"'
544
+ query << conditions[0].to_s
545
+ parameters += ', '+conditions[1..-1].collect{|p| sanitize_conditions(p)}.join(', ') if conditions.size>1
546
+ # query << ')'
547
+ else
548
+ raise Exception.new("First element of an Array can only be String or Symbol.")
549
+ end
550
+ end
551
+
552
+ select = (model.table_name+".id AS id, "+attributes_hash.collect{|k,v| v+" AS "+k}.join(", ")).inspect
553
+ joins = options[:joins] ? ", :joins=>"+options[:joins].inspect : ""
554
+
555
+ code = ""
556
+ code << "conditions = [#{query.join(' AND ').inspect+parameters}]\n"
557
+ code << "search = params[:search]\n"
558
+ code << "words = search.lower.split(/[\\s\\,]+/)\n"
559
+ code << "if words.size > 0\n"
560
+ code << " conditions[0] << '#{' AND ' if query.size>0}('\n"
561
+ code << " words.each_index do |index|\n"
562
+ code << " word = words[index].to_s\n"
563
+ code << " conditions[0] << ') AND (' if index > 0\n"
564
+
565
+ if ActiveRecord::Base.connection.adapter_name == "MySQL"
566
+ code << " conditions[0] << "+attributes.collect{|key| "LOWER(CAST(#{key[0]} AS CHAR)) LIKE ?"}.join(' OR ').inspect+"\n"
567
+ else
568
+ code << " conditions[0] << "+attributes.collect{|key| "LOWER(CAST(#{key[0]} AS VARCHAR)) LIKE ?"}.join(' OR ').inspect+"\n"
569
+ end
570
+
571
+ code << " conditions += ["+attributes.collect{|key| key[1].inspect.gsub('X', '"+word+"').gsub(/(^\"\"\+|\+\"\"\+|\+\"\")/, '')}.join(", ")+"]\n"
572
+ code << " end\n"
573
+ code << " conditions[0] << ')'\n"
574
+ code << "end\n"
575
+ order = ", :order=>"+attributes.collect{|key| "#{key[0]} ASC"}.join(', ').inspect
576
+ limit = ", :limit=>"+(options[:limit]||12).to_s
577
+ partial = options[:partial]
578
+
579
+ html = "<ul><%for #{foreign_record} in #{foreign_records}-%><li id='<%=#{foreign_record}.id-%>'>"
580
+ html << "<%content=#{foreign_record}.#{field.item_label}-%>"
581
+ # html << "<%content="+attributes.collect{|key| "#{foreign_record}['#{key[2]}'].to_s"}.join('+", "+')+" -%>"
582
+ if partial
583
+ html << "<%=render(:partial=>#{partial.inspect}, :locals =>{:#{foreign_record}=>#{foreign_record}, :content=>content, :search=>search})-%>"
584
+ else
585
+ html << "<%=highlight(content, search)-%>"
586
+ end
587
+ html << '</li><%end-%></ul>'
588
+
589
+ code << "#{foreign_records} = #{field_datasource(field)}.find(:all, :conditions=>conditions"+joins+order+limit+")\n"
590
+ code << "render :inline=>#{html.inspect}, :locals=>{:#{foreign_records}=>#{foreign_records}, :search=>search}\n"
591
+ return code
592
+ end
593
+
594
+
595
+
596
+ end
597
+
598
+ end
data/lib/formize.rb ADDED
@@ -0,0 +1,34 @@
1
+ # Formize provides controller's side defined forms.
2
+ module Formize
3
+
4
+ def self.configure(name, value = nil)
5
+ unless self.respond_to?("#{name}=")
6
+ mattr_accessor(name)
7
+ self.send("#{name}=", value)
8
+ end
9
+ end
10
+
11
+ # default_source used by mono_choices:
12
+ # - :foreign_class : Class of foreign object
13
+ # - :class : Class of object
14
+ # - "variable_name" or :variable_name : A variable (Class name is computed with the name
15
+ # of the variable. Example: "product" will have "Product" class_name. If class_name
16
+ # has to be different, use next possibility.
17
+ # - ["variable_name", "class_name"] : Code used to select source with the
18
+ # class_name of the variable.
19
+ configure :default_source, :foreign_class
20
+
21
+ # How many radio can be displayed before to become a +select+
22
+ configure :radio_count_max, 3
23
+
24
+ # How many select options can be displayed before to become a +unroll+
25
+ configure :select_count_max, 7
26
+
27
+ end
28
+
29
+ require 'action_view'
30
+ require 'formize/definition'
31
+ require 'formize/generator'
32
+ require 'formize/form_helper'
33
+ require 'formize/action_pack'
34
+
data/test/helper.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ require 'formize'
7
+
8
+ class Test::Unit::TestCase
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestFormize < Test::Unit::TestCase
4
+ def test_something_for_real
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end