super_form 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/field.rb +15 -9
- data/lib/field/bare.rb +3 -0
- data/lib/field/base.rb +54 -15
- data/lib/field/cnpj.rb +5 -7
- data/lib/field/cpf.rb +6 -8
- data/lib/field/email.rb +4 -4
- data/lib/field/float.rb +7 -0
- data/lib/field/form.rb +30 -0
- data/lib/field/form_array.rb +32 -0
- data/lib/field/form_proxy.rb +16 -0
- data/lib/field/password.rb +6 -10
- data/lib/field/person_type.rb +0 -4
- data/lib/field/telephone.rb +2 -7
- data/lib/person_type.rb +2 -8
- data/lib/presenter.rb +90 -0
- data/lib/presenter/cnpj.rb +9 -0
- data/lib/presenter/cpf.rb +9 -0
- data/lib/presenter/form.rb +20 -0
- data/lib/presenter/password.rb +7 -0
- data/lib/presenter/person_type.rb +9 -0
- data/lib/presenter/telephone.rb +9 -0
- data/lib/super_form.rb +21 -156
- data/lib/super_form/fieldable.rb +78 -0
- data/lib/super_form/fieldset.rb +32 -0
- data/lib/super_form/version.rb +1 -1
- data/spec/lib/field/form_array.rb +71 -0
- data/spec/lib/field/form_array_spec.rb +71 -0
- data/spec/lib/field/form_spec.rb +68 -0
- data/spec/lib/field_spec.rb +13 -0
- data/spec/lib/person_type_spec.rb +66 -0
- data/spec/lib/presenter/cnpj_spec.rb +9 -0
- data/spec/lib/presenter/cpf_spec.rb +9 -0
- data/spec/lib/presenter/form_spec.rb +39 -0
- data/spec/lib/presenter/password_spec.rb +8 -0
- data/spec/lib/presenter/person_type_spec.rb +8 -0
- data/spec/lib/presenter/telephone_spec.rb +9 -0
- data/spec/lib/presenter_spec.rb +166 -0
- data/spec/lib/super_form/fieldable_spec.rb +82 -0
- data/spec/lib/super_form_spec.rb +120 -65
- data/spec/lib/telephone_spec.rb +32 -0
- data/spec/spec_helper.rb +4 -11
- data/spec/support/presenter_name.rb +28 -0
- data/super_form.gemspec +1 -0
- metadata +60 -2
@@ -0,0 +1,20 @@
|
|
1
|
+
module Presenter
|
2
|
+
class Form < Base
|
3
|
+
def self.factory(form)
|
4
|
+
presenters = form.fields.each_with_object({}) do |field, p|
|
5
|
+
name, field = field
|
6
|
+
p[name] = field.presenter_class if field.presenter_class
|
7
|
+
end
|
8
|
+
|
9
|
+
presenter_class = Class.new(Base) do
|
10
|
+
map presenters
|
11
|
+
|
12
|
+
def self.__name__
|
13
|
+
'form'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
presenter_class.new(form)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/super_form.rb
CHANGED
@@ -1,39 +1,23 @@
|
|
1
|
-
require "super_form/version"
|
2
|
-
|
3
|
-
require 'field'
|
4
|
-
require 'attribute'
|
5
|
-
require 'virtus'
|
6
|
-
require 'active_support/inflector'
|
7
1
|
require 'active_support/concern'
|
8
|
-
require '
|
2
|
+
require 'virtus'
|
3
|
+
require 'super_form/fieldable'
|
4
|
+
require "super_form/version"
|
9
5
|
|
10
6
|
autoload :UniquenessValidator, 'uniqueness_validator'
|
11
7
|
|
12
8
|
module SuperForm
|
13
|
-
|
14
|
-
|
15
|
-
Virtus.model(@virtus_options)
|
16
|
-
else
|
17
|
-
Virtus.model
|
18
|
-
end
|
19
|
-
|
20
|
-
klass.include virtus
|
21
|
-
klass.include ActiveModel::Conversion
|
22
|
-
klass.include ActiveModel::Validations
|
23
|
-
klass.extend ActiveModel::Naming
|
24
|
-
klass.extend ActiveModel::Callbacks
|
25
|
-
klass.extend ClassMethods
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
include Fieldable
|
26
11
|
|
27
|
-
|
28
|
-
|
12
|
+
included do
|
13
|
+
include Virtus.model
|
29
14
|
|
30
|
-
|
31
|
-
|
32
|
-
@virtus_options = nil
|
15
|
+
class_eval &SuperForm.callbacks
|
16
|
+
class_eval &SuperForm.constructor
|
33
17
|
end
|
34
18
|
|
35
|
-
def self.
|
36
|
-
|
19
|
+
def self.constructor
|
20
|
+
Proc.new do
|
37
21
|
alias_method :original_initializer, :initialize
|
38
22
|
|
39
23
|
def initialize(*args)
|
@@ -43,8 +27,8 @@ module SuperForm
|
|
43
27
|
end
|
44
28
|
end
|
45
29
|
|
46
|
-
def self.
|
47
|
-
|
30
|
+
def self.callbacks
|
31
|
+
Proc.new do
|
48
32
|
alias_method :ar_valid?, :valid?
|
49
33
|
|
50
34
|
def valid?
|
@@ -57,40 +41,16 @@ module SuperForm
|
|
57
41
|
end
|
58
42
|
end
|
59
43
|
|
60
|
-
def self.base(virtus_options = {})
|
61
|
-
@virtus_options = virtus_options
|
62
|
-
Form
|
63
|
-
end
|
64
|
-
|
65
44
|
def setup
|
66
|
-
|
67
|
-
|
45
|
+
if self.class.setup
|
46
|
+
instance_eval(&self.class.setup)
|
47
|
+
end
|
68
48
|
end
|
69
49
|
|
70
50
|
def persisted?
|
71
51
|
false
|
72
52
|
end
|
73
53
|
|
74
|
-
def fields
|
75
|
-
@fields
|
76
|
-
end
|
77
|
-
|
78
|
-
def field(name)
|
79
|
-
if self.class.form?(name)
|
80
|
-
send(name)
|
81
|
-
else
|
82
|
-
@fields.fetch(name)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def form?
|
87
|
-
true
|
88
|
-
end
|
89
|
-
|
90
|
-
def form_label
|
91
|
-
self.class.name.to_s.gsub(/Form$/, '').humanize
|
92
|
-
end
|
93
|
-
|
94
54
|
def save
|
95
55
|
if valid?
|
96
56
|
run_callbacks :save do
|
@@ -102,25 +62,9 @@ module SuperForm
|
|
102
62
|
end
|
103
63
|
end
|
104
64
|
|
105
|
-
|
106
|
-
|
107
|
-
def initialize_fields
|
108
|
-
@fields = {}
|
109
|
-
@fieldsets = {}
|
65
|
+
def persist!; end
|
110
66
|
|
111
|
-
|
112
|
-
self.class.fields.each do |id, field|
|
113
|
-
if self.class.form?(id)
|
114
|
-
@fields[id] = field
|
115
|
-
|
116
|
-
fieldset = self.class.child_form_fieldsets[id]
|
117
|
-
(@fieldsets[fieldset] ||= []) << @fields[id]
|
118
|
-
else
|
119
|
-
@fields[id] = field.dup
|
120
|
-
(@fieldsets[field.fieldset] ||= []) << @fields[id]
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
67
|
+
private
|
124
68
|
|
125
69
|
module ClassMethods
|
126
70
|
def setup(&block)
|
@@ -128,88 +72,9 @@ module SuperForm
|
|
128
72
|
@setup
|
129
73
|
end
|
130
74
|
|
131
|
-
def
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
# fieldset may be extracted as a domain object
|
136
|
-
def fieldset(id)
|
137
|
-
initialize_fieldset(id)
|
138
|
-
yield
|
139
|
-
close_fieldset
|
140
|
-
end
|
141
|
-
|
142
|
-
def child_form_fieldsets
|
143
|
-
@child_form_fieldsets ||= {}
|
144
|
-
end
|
145
|
-
|
146
|
-
# take care of branches here
|
147
|
-
def field(name, field_class, options = {})
|
148
|
-
if field_class.ancestors.include? SuperForm
|
149
|
-
child_form_fieldsets[name] = current_fieldset_name
|
150
|
-
attribute name, field_class
|
151
|
-
|
152
|
-
define_method(name) do
|
153
|
-
var = :"@#{name.to_s}"
|
154
|
-
value = instance_variable_get(var)
|
155
|
-
|
156
|
-
unless value
|
157
|
-
value = instance_variable_set(var, field_class.new)
|
158
|
-
end
|
159
|
-
|
160
|
-
value
|
161
|
-
end
|
162
|
-
|
163
|
-
create_child_validation(name)
|
164
|
-
field = name
|
165
|
-
else
|
166
|
-
field = field_class.new(name, current_fieldset_name)
|
167
|
-
|
168
|
-
field.add_validations(self, options)
|
169
|
-
field.add_attributes(self, options)
|
170
|
-
|
171
|
-
alias_method :"original_#{name.to_s}=", "#{name}="
|
172
|
-
|
173
|
-
define_method "#{name}=" do |value|
|
174
|
-
field = self.field(name)
|
175
|
-
field.value = value if field
|
176
|
-
|
177
|
-
send "original_#{name.to_s}=", value
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
fields[name] = field
|
182
|
-
end
|
183
|
-
|
184
|
-
def fields
|
185
|
-
@fields ||= {}
|
186
|
-
end
|
187
|
-
|
188
|
-
private
|
189
|
-
|
190
|
-
def initialize_fieldset(id)
|
191
|
-
@current = id
|
192
|
-
end
|
193
|
-
|
194
|
-
def close_fieldset
|
195
|
-
@current = nil
|
196
|
-
end
|
197
|
-
|
198
|
-
def current_fieldset_name
|
199
|
-
@current ||= default_fieldset_name
|
200
|
-
end
|
201
|
-
|
202
|
-
def default_fieldset_name
|
203
|
-
:general
|
204
|
-
end
|
205
|
-
|
206
|
-
def create_child_validation(name)
|
207
|
-
validate :"ensure_valid_#{name.to_s}"
|
208
|
-
|
209
|
-
define_method "ensure_valid_#{name.to_s}" do
|
210
|
-
unless send(name).send(:valid?)
|
211
|
-
errors.add(:base, "Invalid #{name.to_s}")
|
212
|
-
end
|
75
|
+
def model_name
|
76
|
+
if name = self.name || self.to_s
|
77
|
+
ActiveModel::Name.new(self, nil, name.gsub(/Form$/, ''))
|
213
78
|
end
|
214
79
|
end
|
215
80
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_model'
|
3
|
+
require 'field'
|
4
|
+
|
5
|
+
module SuperForm
|
6
|
+
module Fieldable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
include ActiveModel::Model
|
9
|
+
|
10
|
+
def fields
|
11
|
+
@fields ||= self.class.fields.each_with_object({}) do |field, f|
|
12
|
+
f[field.name] = field.dup
|
13
|
+
f[field.name].form = self
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def field(name)
|
18
|
+
fields.fetch(name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def fieldsets
|
22
|
+
@fieldsets ||= self.class.fieldsets.each_with_object({}) do |fieldset, f|
|
23
|
+
id, fields = fieldset
|
24
|
+
|
25
|
+
fields.each_with_object(f) do |field|
|
26
|
+
(f[id] ||= Fieldset.new(id)) << self.field(field)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def fieldset(id)
|
32
|
+
fieldsets.fetch(id)
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
def field(field_id, field_class, options = {})
|
37
|
+
field = field_class.factory(field_id, options)
|
38
|
+
add_field(field)
|
39
|
+
end
|
40
|
+
|
41
|
+
def fields
|
42
|
+
@fields ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
def fieldset(id)
|
46
|
+
open_fieldset(id)
|
47
|
+
yield
|
48
|
+
close_fieldset
|
49
|
+
end
|
50
|
+
|
51
|
+
def fieldsets
|
52
|
+
@fieldsets ||= {}
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def add_field(field)
|
58
|
+
field.setup_container(self)
|
59
|
+
|
60
|
+
fields << field
|
61
|
+
current_fieldset << field.name
|
62
|
+
end
|
63
|
+
|
64
|
+
def open_fieldset(id)
|
65
|
+
@current = id
|
66
|
+
fieldsets[@current] ||= []
|
67
|
+
end
|
68
|
+
|
69
|
+
def close_fieldset
|
70
|
+
@current = nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def current_fieldset
|
74
|
+
fieldsets[@current] || open_fieldset(:default)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module SuperForm
|
2
|
+
class Fieldset
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :id, :fields
|
6
|
+
|
7
|
+
def initialize(id)
|
8
|
+
@id = id
|
9
|
+
@fields = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_field(field)
|
13
|
+
@fields[field.name] = field
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(field)
|
17
|
+
add_field(field)
|
18
|
+
end
|
19
|
+
|
20
|
+
def field(field_id)
|
21
|
+
@fields[field_id]
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](field_id)
|
25
|
+
field(field_id)
|
26
|
+
end
|
27
|
+
|
28
|
+
def each(&block)
|
29
|
+
@fields.each { |field_id| block.call(field_id) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/super_form/version.rb
CHANGED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'super_form'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Field::FormArray do
|
5
|
+
context 'when creating a form collection field' do
|
6
|
+
it 'assigns an array of child forms to the field attribute' do
|
7
|
+
child_form = Class.new { include SuperForm }
|
8
|
+
|
9
|
+
field = Field::FormArray.new(:fake)
|
10
|
+
field.form_class = child_form
|
11
|
+
|
12
|
+
expect(field.attribute).to eq Array[child_form]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when the form field has a container' do
|
17
|
+
before do
|
18
|
+
@child_form = Class.new do
|
19
|
+
include SuperForm
|
20
|
+
|
21
|
+
field :name, Field::Text, presence: true
|
22
|
+
end
|
23
|
+
|
24
|
+
parent_form = Class.new { include SuperForm }
|
25
|
+
|
26
|
+
field = Field::FormArray.new(:child_form)
|
27
|
+
field.form_class = @child_form
|
28
|
+
field.setup_container(parent_form)
|
29
|
+
|
30
|
+
@parent_form = parent_form.new
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#inject_attributes' do
|
34
|
+
it 'injects attributes into the parent form' do
|
35
|
+
expect(@parent_form).to respond_to :child_form=
|
36
|
+
expect(@parent_form).to respond_to :child_form
|
37
|
+
expect(@parent_form.child_form).to eq []
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#inject validations' do
|
42
|
+
it 'forces the parent object to validate the child object' do
|
43
|
+
@parent_form.child_form = [@child_form.new, @child_form.new, @child_form.new]
|
44
|
+
@parent_form.save
|
45
|
+
errors = [
|
46
|
+
'Invalid child_form on row 1',
|
47
|
+
'Invalid child_form on row 2',
|
48
|
+
'Invalid child_form on row 3'
|
49
|
+
]
|
50
|
+
expect(@parent_form.errors[:base]).to eq(errors)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#[]' do
|
56
|
+
before do
|
57
|
+
@child_form = Class.new { include SuperForm }
|
58
|
+
proxy = Field::FormArray[@child_form]
|
59
|
+
|
60
|
+
@field = proxy.factory(:name)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'creates a form instance' do
|
64
|
+
expect(@field).to be_instance_of(Field::FormArray)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'stores the child form into the form_class attribute' do
|
68
|
+
expect(@field.form_class).to eq @child_form
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|