super_form 0.0.1 → 0.1.0

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/field.rb +15 -9
  3. data/lib/field/bare.rb +3 -0
  4. data/lib/field/base.rb +54 -15
  5. data/lib/field/cnpj.rb +5 -7
  6. data/lib/field/cpf.rb +6 -8
  7. data/lib/field/email.rb +4 -4
  8. data/lib/field/float.rb +7 -0
  9. data/lib/field/form.rb +30 -0
  10. data/lib/field/form_array.rb +32 -0
  11. data/lib/field/form_proxy.rb +16 -0
  12. data/lib/field/password.rb +6 -10
  13. data/lib/field/person_type.rb +0 -4
  14. data/lib/field/telephone.rb +2 -7
  15. data/lib/person_type.rb +2 -8
  16. data/lib/presenter.rb +90 -0
  17. data/lib/presenter/cnpj.rb +9 -0
  18. data/lib/presenter/cpf.rb +9 -0
  19. data/lib/presenter/form.rb +20 -0
  20. data/lib/presenter/password.rb +7 -0
  21. data/lib/presenter/person_type.rb +9 -0
  22. data/lib/presenter/telephone.rb +9 -0
  23. data/lib/super_form.rb +21 -156
  24. data/lib/super_form/fieldable.rb +78 -0
  25. data/lib/super_form/fieldset.rb +32 -0
  26. data/lib/super_form/version.rb +1 -1
  27. data/spec/lib/field/form_array.rb +71 -0
  28. data/spec/lib/field/form_array_spec.rb +71 -0
  29. data/spec/lib/field/form_spec.rb +68 -0
  30. data/spec/lib/field_spec.rb +13 -0
  31. data/spec/lib/person_type_spec.rb +66 -0
  32. data/spec/lib/presenter/cnpj_spec.rb +9 -0
  33. data/spec/lib/presenter/cpf_spec.rb +9 -0
  34. data/spec/lib/presenter/form_spec.rb +39 -0
  35. data/spec/lib/presenter/password_spec.rb +8 -0
  36. data/spec/lib/presenter/person_type_spec.rb +8 -0
  37. data/spec/lib/presenter/telephone_spec.rb +9 -0
  38. data/spec/lib/presenter_spec.rb +166 -0
  39. data/spec/lib/super_form/fieldable_spec.rb +82 -0
  40. data/spec/lib/super_form_spec.rb +120 -65
  41. data/spec/lib/telephone_spec.rb +32 -0
  42. data/spec/spec_helper.rb +4 -11
  43. data/spec/support/presenter_name.rb +28 -0
  44. data/super_form.gemspec +1 -0
  45. metadata +60 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a5f0e95c7ffd7c811db1288e98272f0544bcacaa
4
- data.tar.gz: f5e6d6330f0524b513fdf6cf4b4305cf90e32a1d
3
+ metadata.gz: 61ec845a89d382bcafc1395324d331ca94e86e78
4
+ data.tar.gz: de0a636fc0d8b72884d35ff42f6593c54d1791a1
5
5
  SHA512:
6
- metadata.gz: 7617b22b0f8b2530b9ec7a08cc3ba3e79f7b87f3526a6f3ecadea596b9ccb2ccc45121afd5ada9a95b57ff87d42707638e3818b49c618c2e6e1d5cb1019c502c
7
- data.tar.gz: af71f75d3eb608ba7975890d02c9379a2f398c567720cc1e4e2997b5814101e58342acffbb6a5715b3a0f5828a7a62e69f5e1ea642fb1021a37b06b54d0ceb8b
6
+ metadata.gz: 2d10f75ebf0978ca8c0dec009fdfaeb9129fe814ece7b4646b064fd5ef59a3be5ec679bf8361ec2ad2c66a319e289f4c06189392df724ffe0fa2eaebf2e8ce23
7
+ data.tar.gz: f399675c1e2e55d1dcf1e299b42acf73502a05e3e035c8aae5fa20c2eb5c3736e86fda5a2bb4237d9dbe7c9ab337ac53ae06d683befd4d8a012336d3d4bcdbee
data/lib/field.rb CHANGED
@@ -1,11 +1,17 @@
1
+ require 'attribute'
2
+ require 'super_form/fieldset'
3
+
1
4
  module Field
2
- autoload :Error, 'field/error'
3
- autoload :Base, 'field/base'
4
- autoload :Text, 'field/text'
5
- autoload :Password, 'field/password'
6
- autoload :Email, 'field/email'
7
- autoload :CPF, 'field/cpf'
8
- autoload :CNPJ, 'field/cnpj'
9
- autoload :Telephone, 'field/telephone'
10
- autoload :PersonType, 'field/person_type'
5
+ autoload :Error, 'field/error'
6
+ autoload :Base, 'field/base'
7
+ autoload :Text, 'field/text'
8
+ autoload :Form, 'field/form'
9
+ autoload :FormArray, 'field/form_array'
10
+ autoload :Password, 'field/password'
11
+ autoload :Email, 'field/email'
12
+ autoload :Float, 'field/float'
13
+ autoload :CPF, 'field/cpf'
14
+ autoload :CNPJ, 'field/cnpj'
15
+ autoload :Telephone, 'field/telephone'
16
+ autoload :PersonType, 'field/person_type'
11
17
  end
data/lib/field/bare.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Field
2
+ class Bare < Base; end
3
+ end
data/lib/field/base.rb CHANGED
@@ -1,35 +1,74 @@
1
1
  module Field
2
2
  class Base
3
3
  attr_accessor :name
4
+ attr_accessor :options
4
5
  attr_accessor :form
5
- attr_accessor :value
6
- attr_reader :fieldset
7
6
 
8
- def initialize(name, fieldset)
9
- @name = name
10
- @fieldset = fieldset
7
+ def self.factory(*args)
8
+ new(*args)
11
9
  end
12
10
 
13
- def add_attributes(klass, options)
14
- klass.attribute name, self.attribute
11
+ def initialize(name, options = {})
12
+ @name = name
13
+ @options = options
15
14
  end
16
15
 
17
- def add_validations(klass, options)
18
- if options.any?
19
- klass.send(:validates, name, options)
16
+ def setup_container(container)
17
+ @container = container
18
+
19
+ if Helper.container_is_virtus?(container)
20
+ inject_attributes
20
21
  end
21
- end
22
22
 
23
- def form?
24
- false
23
+ inject_validations
25
24
  end
26
25
 
27
26
  def attribute
28
27
  String
29
28
  end
30
29
 
31
- def output
32
- value
30
+ def inject_attributes
31
+ @container.attribute @name, attribute
32
+ end
33
+
34
+ def inject_validations
35
+ if @options.any?
36
+ @container.send(:validates, @name, @options)
37
+ end
38
+ end
39
+
40
+ def value
41
+ @form.send(name) if @form
42
+ end
43
+
44
+ def presenter_class
45
+ nil
46
+ end
47
+ end
48
+
49
+ module Helper
50
+ def self.container_is_virtus?(container)
51
+ defined?(Virtus::Model::Core) &&
52
+ container.ancestors.include?(Virtus::Model::Core)
53
+ end
54
+ end
55
+
56
+ class Proxy
57
+ def initialize(options, &setup)
58
+ @options = options
59
+ @setup = setup
60
+ end
61
+
62
+ def factory(name, options = {})
63
+ @setup.call(name, options, self)
64
+ end
65
+
66
+ def method_missing(id, *args)
67
+ @options[id] || super
68
+ end
69
+
70
+ def respond_to_missing?(method_name, include_private = false)
71
+ @options.key? method_name
33
72
  end
34
73
  end
35
74
  end
data/lib/field/cnpj.rb CHANGED
@@ -3,8 +3,8 @@ require 'cnpj_validator'
3
3
 
4
4
  module Field
5
5
  class CNPJ < Base
6
- def add_validations(klass, options)
7
- klass.validates name, cnpj: true
6
+ def inject_validations
7
+ @container.validates name, cnpj: true
8
8
 
9
9
  if options[:uniqueness]
10
10
  unless options[:uniqueness].is_a?(Hash) && options[:uniqueness][:model]
@@ -17,7 +17,9 @@ module Field
17
17
  allow_blank: true
18
18
  }
19
19
 
20
- klass.validates name, uniqueness: options[:uniqueness].merge(required)
20
+ options[:uniqueness].merge!(required)
21
+ @container.validates name, uniqueness: options[:uniqueness]
22
+
21
23
  options.reject! { |k| k == :uniqueness }
22
24
  end
23
25
 
@@ -27,9 +29,5 @@ module Field
27
29
  def attribute
28
30
  ::Attribute::CNPJ
29
31
  end
30
-
31
- def output
32
- ::CNPJ.new(value).formatted
33
- end
34
32
  end
35
33
  end
data/lib/field/cpf.rb CHANGED
@@ -2,9 +2,9 @@ require 'cpf'
2
2
  require 'cpf_validator'
3
3
 
4
4
  module Field
5
- class CPF < ::Field::Base
6
- def add_validations(klass, options)
7
- klass.validates name, cpf: true
5
+ class CPF < Base
6
+ def inject_validations
7
+ @container.validates name, cpf: true
8
8
 
9
9
  if options[:uniqueness]
10
10
  unless options[:uniqueness].is_a?(Hash) && options[:uniqueness][:model]
@@ -17,7 +17,9 @@ module Field
17
17
  allow_blank: true
18
18
  }
19
19
 
20
- klass.validates name, uniqueness: options[:uniqueness].merge(required)
20
+ options[:uniqueness].merge!(required)
21
+ @container.validates name, uniqueness: options[:uniqueness]
22
+
21
23
  options.reject! { |k| k == :uniqueness }
22
24
  end
23
25
 
@@ -27,9 +29,5 @@ module Field
27
29
  def attribute
28
30
  ::Attribute::CPF
29
31
  end
30
-
31
- def output
32
- ::CPF.new(value).formatted
33
- end
34
32
  end
35
33
  end
data/lib/field/email.rb CHANGED
@@ -2,9 +2,9 @@ require 'validates_email_format_of'
2
2
 
3
3
  module Field
4
4
  class Email < Base
5
- def add_validations(klass, options)
6
- klass.validates name, length: { maximum: 155 }
7
- klass.validates name, email_format: {
5
+ def inject_validations
6
+ @container.validates name, length: { maximum: 155 }
7
+ @container.validates name, email_format: {
8
8
  message: I18n.t('activemodel.errors.messages.email'),
9
9
  allow_nil: true,
10
10
  allow_blank: true
@@ -22,7 +22,7 @@ module Field
22
22
  allow_blank: true
23
23
  }
24
24
 
25
- klass.validates name, uniqueness: options[:uniqueness].merge(required)
25
+ @container.validates name, uniqueness: options[:uniqueness].merge(required)
26
26
  options.reject! { |k| k == :uniqueness }
27
27
  end
28
28
 
@@ -0,0 +1,7 @@
1
+ module Field
2
+ class Float < Base
3
+ def attribute
4
+ Float
5
+ end
6
+ end
7
+ end
data/lib/field/form.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'field/form_proxy'
2
+
3
+ module Field
4
+ class Form < Base
5
+ extend FormProxy
6
+
7
+ attr_accessor :form_class
8
+
9
+ def inject_attributes
10
+ @container.attribute @name, attribute, default: attribute.new
11
+ end
12
+
13
+ def inject_validations
14
+ @container.class_eval %Q{
15
+ method = "__ensure_valid_#{name.to_s}__"
16
+ validate method
17
+
18
+ define_method method do
19
+ unless send('#{name}').send(:valid?)
20
+ errors.add(:base, "Invalid #{name.to_s}")
21
+ end
22
+ end
23
+ }
24
+ end
25
+
26
+ def attribute
27
+ @form_class
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,32 @@
1
+ require 'field/form_proxy'
2
+
3
+ module Field
4
+ class FormArray < Base
5
+ extend FormProxy
6
+
7
+ attr_accessor :form_class
8
+
9
+ def inject_attributes
10
+ @container.attribute @name, attribute
11
+ end
12
+
13
+ def inject_validations
14
+ @container.class_eval %Q{
15
+ method = "__ensure_valid_#{name.to_s}__"
16
+ validate method
17
+
18
+ define_method method do
19
+ #{name}.each_with_index do |form, i|
20
+ unless form.send(:valid?)
21
+ errors.add(:base, "Invalid #{name.to_s} on row \#\{i + 1\}")
22
+ end
23
+ end
24
+ end
25
+ }
26
+ end
27
+
28
+ def attribute
29
+ Array[@form_class]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ module Field
2
+ module FormProxy
3
+ def [](form_class)
4
+ extra = {
5
+ form_class: form_class,
6
+ field_class: self
7
+ }
8
+
9
+ Proxy.new(extra) do |name, options, proxy|
10
+ field = proxy.field_class.new(name, options)
11
+ field.form_class = proxy.form_class
12
+ field
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,21 +1,17 @@
1
1
  module Field
2
2
  class Password < Base
3
- def add_attributes(klass, options)
4
- klass.attribute :"#{name}_confirmation", String
3
+ def inject_attributes
4
+ @container.attribute :"#{name}_confirmation", String
5
5
 
6
6
  super
7
7
  end
8
8
 
9
- def add_validations(klass, options)
10
- klass.validates name, presence: true, if: ->(f){ !f.to_param }
11
- klass.validates name, confirmation: true, if: ->(f){ !f.to_param }
12
- klass.validates name, length: { minimum: 5, maximum: 15 }, allow_blank: true
9
+ def add_validations
10
+ @container.validates name, presence: true, if: ->(f){ !f.to_param }
11
+ @container.validates name, confirmation: true, if: ->(f){ !f.to_param }
12
+ @container.validates name, length: { minimum: 5, maximum: 15 }, allow_blank: true
13
13
 
14
14
  super
15
15
  end
16
-
17
- def output
18
- nil
19
- end
20
16
  end
21
17
  end
@@ -5,9 +5,5 @@ module Field
5
5
  def attribute
6
6
  ::Attribute::PersonType
7
7
  end
8
-
9
- def output
10
- ::PersonType.new(value).description
11
- end
12
8
  end
13
9
  end
@@ -3,8 +3,8 @@ require 'telephone_validator'
3
3
 
4
4
  module Field
5
5
  class Telephone < Base
6
- def add_validations(klass, options)
7
- klass.validates name, telephone: true
6
+ def inject_validations
7
+ @container.validates name, telephone: true
8
8
 
9
9
  super
10
10
  end
@@ -12,10 +12,5 @@ module Field
12
12
  def attribute
13
13
  ::Attribute::Telephone
14
14
  end
15
-
16
- def output
17
- return unless value
18
- ::Telephone.new(value).formatted
19
- end
20
15
  end
21
16
  end
data/lib/person_type.rb CHANGED
@@ -14,8 +14,8 @@ class PersonType
14
14
  end
15
15
 
16
16
  def self.descriptions
17
- TYPES.each_with_object({}) do |type, hash|
18
- hash[type] = description(type)
17
+ TYPES.each_with_object({}) do |type, hash|
18
+ hash[type] = description(type)
19
19
  end
20
20
  end
21
21
 
@@ -42,10 +42,4 @@ class PersonType
42
42
  def to_s
43
43
  value
44
44
  end
45
-
46
- class Attribute < Virtus::Attribute
47
- def coerce(value)
48
- ::PersonType.new(value).value
49
- end
50
- end
51
45
  end
data/lib/presenter.rb ADDED
@@ -0,0 +1,90 @@
1
+ require 'delegate'
2
+ require 'active_support/inflector'
3
+
4
+ module Presenter
5
+ autoload :CPF, 'presenter/cpf'
6
+ autoload :CNPJ, 'presenter/cnpj'
7
+ autoload :Telephone, 'presenter/telephone'
8
+ autoload :Password, 'presenter/password'
9
+ autoload :PersonType, 'presenter/person_type'
10
+ autoload :Form, 'presenter/form'
11
+
12
+ module Name
13
+ def __name__
14
+ if name.nil?
15
+ raise 'You must define __name__ on a presenter anonymous class'
16
+ end
17
+
18
+ name.demodulize.underscore.gsub(/_presenter$/, '')
19
+ end
20
+ end
21
+
22
+ class Base < SimpleDelegator
23
+ extend Name
24
+
25
+ def self.map(params)
26
+ params.each { |p| setup_attribute(p) }
27
+ end
28
+
29
+ def self.use(*presenters)
30
+ params = presenters.each_with_object({}) do |id, p|
31
+ p[id] = id
32
+ end
33
+
34
+ map params
35
+ end
36
+
37
+ private
38
+
39
+ def self.setup_attribute(params)
40
+ attribute, presenter = params
41
+ presenter_name = presenter.is_a?(Class) ? presenter.__name__ : presenter
42
+ method = "#{presenter_name}_presenter"
43
+
44
+ def_presenter_accessor(presenter, method)
45
+ def_attribute_reader(attribute, method)
46
+ end
47
+
48
+ def self.def_presenter_accessor(presenter, method)
49
+ attr_writer method
50
+
51
+ define_method(method) do
52
+ instance_variable_get(:"@#{method}") ||
53
+ self.class.find_presenter(presenter)
54
+ end
55
+ end
56
+
57
+ def self.def_attribute_reader(attribute, presenter_method)
58
+ define_method(attribute) do
59
+ presenter = send(presenter_method)
60
+ presenter.value = __getobj__.send(attribute)
61
+ presenter.output
62
+ end
63
+ end
64
+
65
+ def self.find_presenter(presenter)
66
+ return presenter.new if presenter.is_a?(Class)
67
+
68
+ base_class = presenter.to_s.capitalize.camelize
69
+ Object.const_get("Presenter::#{base_class}").new
70
+ end
71
+ end
72
+
73
+ class Each
74
+ extend Name
75
+
76
+ attr_accessor :value
77
+
78
+ def initialize(value = nil)
79
+ self.value = value
80
+ end
81
+
82
+ def output
83
+ value
84
+ end
85
+
86
+ def to_s
87
+ output
88
+ end
89
+ end
90
+ end