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,56 @@
1
+ module Formize
2
+
3
+ # Main class for Form definitions
4
+ # It permits to manage tree of form elements
5
+ class Element
6
+ attr_reader :parent, :children, :method_name, :id
7
+ @@count = 0
8
+
9
+ def initialize(parent = nil, is_method = false)
10
+ @parent = parent
11
+ @children = []
12
+ @is_method = is_method
13
+ @@count += 1
14
+ @id = @@count.to_s(36)
15
+ @method_name = "_formize_#{@id}"
16
+ end
17
+
18
+ def is_method?
19
+ @is_method
20
+ end
21
+
22
+ def is_method!(value = true)
23
+ raise ArgumentError.new("Must be true or false (not #{value.inspect})") unless [TrueClass, FalseClass].include?(value.class)
24
+ @is_method = value
25
+ end
26
+
27
+ def method_name=(name)
28
+ raise ArgumentError.new("Name of field_set must be written only with a-z and 0-9 and _ (not #{name.inspect})") unless name.to_s == name.to_s.downcase.gsub(/[^a-z0-9\_]/, '')
29
+ @method_name = name
30
+ end
31
+
32
+
33
+ def method_code(options={})
34
+ varh = options[:html_variable] ||= 'html'
35
+ code = "def #{method_name}(record)\n"
36
+ code << inner_method_code(options).gsub(/^/, ' ')
37
+ code << " return #{varh}\n"
38
+ code << "end\n"
39
+ return code
40
+ end
41
+
42
+ def method_call_code(options={})
43
+ return inner_method_code(options) unless self.is_method?
44
+ return "#{method_name}(record)"
45
+ end
46
+
47
+ def inner_method_code(options={})
48
+ # raise NotImplementedError.new
49
+ return content_tag(:strong, "'#{self.class.name} does not implement :#{__method__} method'", options)
50
+ end
51
+
52
+
53
+ end
54
+
55
+
56
+ end
@@ -0,0 +1,67 @@
1
+ module Formize
2
+
3
+
4
+ # Represents the field element
5
+ class Field < FormElement
6
+ attr_reader :name, :options, :column, :record_name, :method, :type, :required, :choices, :input_id, :source, :item_label, :field_id, :reflection, :html_options, :default, :search_attributes
7
+
8
+ TYPES = [:check_box, :choice, :date, :datetime, :label, :numeric, :password, :mono_choice, :string, :text_area].freeze
9
+
10
+ def initialize(form, parent, name, options={})
11
+ super(form, parent)
12
+ @name = name.to_s
13
+ @options = (options.is_a?(Hash) ? options : {})
14
+ @column = form.model.columns_hash[@name]
15
+ @record_name = form.record_name
16
+ @method = @name
17
+ unless @options[:default].nil?
18
+ @default = (@options[:default].is_a?(String) ? Code.new(@options[:default]) : @options[:default])
19
+ end
20
+ @html_options = @options.delete(:html_options)||{}
21
+ @depend_on = @options.delete(:depend_on)
22
+ raise ArgumentError.new("A depended element must defined before its dependencies (#{@depended.inspect})") if !@depend_on.blank? and form.fields[@depend_on].nil?
23
+ if type = @options.delete(:as)
24
+ raise ArgumentError.new("Unknown field type (got #{@options[:as].inspect}, expects #{TYPES.join(', ')})") unless TYPES.include? type
25
+ @type = type
26
+ else
27
+ @type = :password if @name.to_s.match /password/
28
+ if @choices = @options.delete(:choices)
29
+ if @choices.is_a? Array
30
+ @type = :choice
31
+ elsif [Symbol, Hash].include? @choices.class
32
+ @type = :mono_choice
33
+ @reflection = form.model.reflections[@method.to_sym]
34
+ @source = @options.delete(:source) # || @reflection.class_name
35
+ @is_method = true if @options[:new]
36
+ @method_name = self.form.unique_name + "_inf_" + @name
37
+ @method = @reflection.primary_key_name
38
+ unless @item_label = @options.delete(:item_label)
39
+ model = @reflection.class_name.constantize
40
+ available_methods = (model.columns_hash.keys+model.instance_methods).collect{|x| x.to_s}
41
+ @item_label = [:label, :name, :code, :number, :inspect].detect{|x| available_methods.include?(x.to_s)}
42
+ end
43
+ @search_attributes = @options[:search] || @reflection.class_name.constantize.content_columns.select{|c| c.type != :boolean and ![:created_at, :updated_at, :lock_version].include?(c.name.to_sym)}.collect{|c| c.name.to_sym}
44
+ else
45
+ raise ArgumentError.new("Option :choices must be Array, Symbol or Hash (got #{@choices.class.name})")
46
+ end
47
+ end
48
+ if column
49
+ @type = :check_box if column.type == :boolean
50
+ @type = :date if column.type == :date
51
+ @type = :datetime if column.type==:datetime or column.type==:timestamp
52
+ @type = :numeric if [:integer, :float, :decimal].include? column.type
53
+ @type = :text_area if column.type == :text
54
+ end
55
+ @type = :label if @form.model.readonly_attributes.include? @record_name
56
+ @type ||= :string
57
+ end
58
+ @required = false
59
+ @required = !@column.null if @column
60
+ @required = true if @options.delete(:required).is_a?(TrueClass)
61
+ @input_id = form.model.name.underscore << '_' << method.to_s
62
+ @field_id = "ff" << Time.now.to_i.to_s(36) << rand.to_s[2..-1].to_i.to_s(36)
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,40 @@
1
+ module Formize
2
+
3
+
4
+
5
+ # Represents a group of fields which can depend on other fields
6
+ class FieldSet < FormElement
7
+ attr_reader :name, :options, :title, :html_options
8
+
9
+ def initialize(form, parent, name=nil, options={})
10
+ super(form, parent)
11
+ @title = nil
12
+ @name = if name.blank?
13
+ rand.to_s[2..-1].to_i.to_s(36)
14
+ else
15
+ raise ArgumentError.new("Name of field_set must be written only with a-z and 0-9 and _ (not #{name.inspect})") unless name.to_s == name.to_s.downcase.gsub(/[^a-z0-9\_]/, '')
16
+ @title = name
17
+ name.to_s
18
+ end
19
+ @depend_on = options.delete(:depend_on)
20
+ raise ArgumentError.new("A depended element must defined before its dependencies (#{@depended.inspect})") if !@depend_on.blank? and form.fields[@depend_on].nil?
21
+ @options = (options.is_a?(Hash) ? options : {})
22
+ @html_options = @options.delete(:html_options)||{}
23
+ end
24
+
25
+
26
+ def field_set(name=nil, options={}, &block)
27
+ raise ArgumentError.new("Missing block") unless block_given?
28
+ field_set = self.new_child(FieldSet, name, options)
29
+ yield field_set
30
+ end
31
+
32
+ def field(name, options={})
33
+ self.new_child(Field, name, options)
34
+ end
35
+
36
+ end
37
+
38
+
39
+
40
+ end
@@ -0,0 +1,89 @@
1
+ module Formize
2
+
3
+ # Represents an environment for a form or list of fields of one Record
4
+ class Form
5
+ attr_reader :model, :elements, :record_name, :unique_name, :options, :id
6
+ @@count = 0
7
+
8
+
9
+ def initialize(name, model, options={})
10
+ @name = name
11
+ @model = model
12
+ @options = options
13
+ @elements = []
14
+ @@count += 1
15
+ @id = @@count.to_s(36)
16
+ @unique_name = @options.delete(:unique_name) unless @options[:unique_name].blank?
17
+ @unique_name ||= "_formize#{@id}"
18
+ @record_name = @model.name.underscore
19
+ end
20
+
21
+ def field_set(name=nil, options={}, &block)
22
+ raise ArgumentError.new("Missing block") unless block_given?
23
+ field_set = new_element(FieldSet, name, options)
24
+ yield field_set
25
+ end
26
+
27
+ def field(name, options={})
28
+ return new_element(Field, name, options)
29
+ end
30
+
31
+ # def inner_method_code(options={})
32
+ # varh = options[:html_variable] || 'html'
33
+ # code = "#{varh} = ''\n"
34
+ # for child in children
35
+ # code << "#{varh} << " << child.method_call_code << "\n"
36
+ # end
37
+ # code << "return #{varh}\n"
38
+ # return code
39
+ # end
40
+
41
+ def controller_method_name
42
+ @options[:controller_method_name] || "formize_#{model.underscore}"
43
+ end
44
+
45
+ def view_method_name
46
+ @options[:method_name] || "_form_#{model.underscore}"
47
+ end
48
+
49
+ def action_name
50
+ @options[:action_name] || :formize
51
+ end
52
+
53
+ # def methodics
54
+ # return elements.collect{|e| e.methodics}.flatten
55
+ # end
56
+
57
+ def mono_choices
58
+ return elements.collect{|e| e.mono_choices}.flatten
59
+ end
60
+
61
+ def fields
62
+ return elements.inject(HashWithIndifferentAccess.new){|h, e| h.merge!(e.fields)}
63
+ end
64
+
65
+ def dependents
66
+ return elements.collect{|e| e.dependents}.flatten
67
+ end
68
+
69
+ def all_elements
70
+ return elements.collect{|e| e.all_elements}.flatten
71
+ end
72
+
73
+ def dependents_on(element)
74
+ return elements.collect{|e| e.dependents_on(element)}.flatten
75
+ end
76
+
77
+
78
+ private
79
+
80
+ def new_element(klass, *args)
81
+ raise ArgumentError.new("Bad child type (#{klass.name}). Must be an Formize::FormElement") unless klass < FormElement
82
+ element = klass.new(self, nil, *args)
83
+ @elements << element
84
+ return element
85
+ end
86
+
87
+ end
88
+
89
+ end
@@ -0,0 +1,140 @@
1
+ module Formize
2
+
3
+ # Main class for form elements
4
+ class FormElement
5
+ attr_reader :form, :parent, :children, :unique_name, :id, :depend_on, :html_id
6
+ @@count = 0
7
+
8
+ def initialize(form, parent = nil)
9
+ raise ArgumentError.new("Bad form (#{form.class.name}). Must be an Formize::Form") unless form.is_a? Formize::Form
10
+ @form = form
11
+ @parent = parent
12
+ @depend_on = nil
13
+ @children = []
14
+ @@count += 1
15
+ @id = @@count.to_s(36)
16
+ @html_id = "fz#{@id}"
17
+ @unique_name = self.form.unique_name + "_" + @html_id
18
+ end
19
+
20
+
21
+ def dependeds
22
+ l = (self.parent ? self.parent.dependeds : [])
23
+ l << {:name=>self.depend_on} unless self.depend_on.blank?
24
+ return l
25
+ end
26
+
27
+ def arguments
28
+ args = []
29
+ args << {:name=>form.record_name}
30
+ # args += self.dependeds
31
+ # args << {:name=>@depend_on} if @depend_on
32
+ return args
33
+ end
34
+
35
+ def prototype
36
+ return "#{@unique_name}(" + arguments.collect{|x| x[:name]}.join(', ') + ")"
37
+ end
38
+
39
+ # def method_name=(name)
40
+ # raise ArgumentError.new("Name of field_set must be written only with a-z and 0-9 and _ (not #{name.inspect})") unless name.to_s == name.to_s.downcase.gsub(/[^a-z0-9\_]/, '')
41
+ # @method_name = name
42
+ # end
43
+
44
+
45
+ # def method_code(options={})
46
+ # varh = options[:html_variable] ||= 'html'
47
+ # code = "def #{method_name}(record)\n"
48
+ # code << inner_method_code(options).gsub(/^/, ' ')
49
+ # code << " return #{varh}\n"
50
+ # code << "end\n"
51
+ # return code
52
+ # end
53
+
54
+ # def method_call_code(options={})
55
+ # return inner_method_code(options) unless self.is_method?
56
+ # return "#{method_name}(record)"
57
+ # end
58
+
59
+ # def inner_method_code(options={})
60
+ # # raise NotImplementedError.new
61
+ # return content_tag(:strong, "'#{self.class.name} does not implement :#{__method__} method'", options)
62
+ # end
63
+
64
+
65
+
66
+ # def is_method?
67
+ # @depend_on.nil?
68
+ # end
69
+
70
+ # def methodics
71
+ # elements = []
72
+ # for child in self.children
73
+ # elements += child.methodics
74
+ # end
75
+ # elements << self if self.is_method?
76
+ # return elements
77
+ # end
78
+
79
+ def mono_choices
80
+ elements = []
81
+ for child in self.children
82
+ elements += child.mono_choices
83
+ end
84
+ elements << self if self.class == Formize::Field and self.type == :mono_choice
85
+ return elements
86
+ end
87
+
88
+ def fields
89
+ elements = HashWithIndifferentAccess.new()
90
+ for child in self.children
91
+ elements.merge!(child.fields)
92
+ end
93
+ elements[self.name] = self if self.class == Formize::Field
94
+ return elements
95
+ end
96
+
97
+ def dependents
98
+ elements = []
99
+ for child in self.children
100
+ elements += child.dependents
101
+ end
102
+ elements << self if self.options[:depend_on]
103
+ return elements
104
+ end
105
+
106
+
107
+ def all_elements
108
+ elements = self.children.collect{|c| c.all_elements}.flatten
109
+ elements << self
110
+ return elements
111
+ end
112
+
113
+
114
+ # Find form elements
115
+ def dependents_on(element)
116
+ elements = []
117
+ for child in self.children
118
+ elements += child.dependents_on(element)
119
+ end
120
+ elements << self if self.depend_on and self.depend_on.to_s == element.name.to_s # form.fields[self.depend_on].name == element.name
121
+ return elements
122
+ end
123
+
124
+
125
+
126
+
127
+ protected
128
+
129
+ def new_child(klass, *args)
130
+ raise ArgumentError.new("Bad child type (#{klass.name}). Must be an Formize::FormElement") unless klass < FormElement
131
+ element = klass.new(self.form, self, *args)
132
+ @children << element
133
+ return element
134
+ end
135
+
136
+
137
+ end
138
+
139
+
140
+ end
@@ -0,0 +1,5 @@
1
+ # require 'formize/definition/element'
2
+ require 'formize/definition/form'
3
+ require 'formize/definition/form_element'
4
+ require 'formize/definition/field_set'
5
+ require 'formize/definition/field'
@@ -0,0 +1,62 @@
1
+ module Formize
2
+ module FormHelper
3
+
4
+ # Generates a form with all its fields as defined in controller.
5
+ # If no name is given, it uses the name of the controller to find the corresponding model
6
+ def formize_form(*args)
7
+ name, options = nil, {}
8
+ name = args[0] if args[0].is_a? Symbol
9
+ options = args[-1] if args[-1].is_a? Hash
10
+ self.send("_#{options[:controller]||self.controller_name}_#{__method__}_#{name||self.controller_name}_tag")
11
+ end
12
+
13
+ # Generates all the fields as defined in controller with the <form> tag.
14
+ # If no name is given, it uses the name of the controller to find the corresponding model
15
+ def formize_fields(*args)
16
+ name, options = nil, {}
17
+ name = args[0] if args[0].is_a? Symbol
18
+ options = args[-1] if args[-1].is_a? Hash
19
+ self.send("_#{options[:controller]||self.controller_name}_#{__method__}_#{name||self.controller_name}_tag")
20
+ end
21
+
22
+ # Permits to use content_tag in helpers with easy add
23
+ def hard_content_tag(name, options={}, escape=true, &block)
24
+ content = ''
25
+ yield content
26
+ return content_tag(name, content, options, escape)
27
+ end
28
+
29
+ # Returns a list of radio buttons for specified attribute (identified by +method+)
30
+ # on an object assigned to the template (identified by +object_name+). It works like +select+
31
+ def radio(object_name, method, choices, options = {}, html_options = {})
32
+ html = ""
33
+ html_options[:class] ||= :rad
34
+ for choice in choices
35
+ html << content_tag(:span, radio_button(object_name, method, choice[1]) + '&nbsp;'.html_safe + label(object_name, method, choice[0], :value=>choice[1]), html_options)
36
+ end
37
+ return html
38
+ end
39
+
40
+ # Returns a text field which has the same behavior of +select+ but with a search
41
+ # action which permits to find easily in very long lists...
42
+ def unroll(object_name, method, choices, options = {}, input_options={}, html_options = {})
43
+ object = instance_variable_get("@#{object_name}")
44
+ label = options[:label]
45
+ if label.is_a?(String) or label.is_a?(Symbol)
46
+ label = Proc.new{|x| x.send(label)}
47
+ elsif !label.is_a?(Proc)
48
+ label = Proc.new{|x| x.inspect}
49
+ end
50
+ html = ""
51
+ html << hidden_field(object_name, method, input_options)
52
+ html << tag(:input, :type=>:text, "data-unroll"=>url_for(choices), "data-value-container"=>"#{object_name}_#{method}", :value=>label.call(object.send(method.to_s.gsub(/_id$/, ''))), :size=>html_options.delete(:size)||32)
53
+ return content_tag(:span, html, html_options)
54
+ end
55
+
56
+
57
+
58
+ end
59
+
60
+ end
61
+
62
+ ActionView::Base.send :include, Formize::FormHelper