simple_params 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZGYzNDdhM2YxYjQzNzI3NWEzOTlkMGRjNDA2M2NiN2NmZjA2ZGFjOQ==
4
+ NjYyNWJhNWU2ZmNkMGMxZWFjMmEzMjM3OWQyNWY0ZWZhNzY2N2ZhNw==
5
5
  data.tar.gz: !binary |-
6
- OGM2ODA5ZWI2ZTVjMDFlY2EwMzhmY2Y2ODM0ZTY5MmY5YjFmYTA0MA==
6
+ NzllYWUzNDJjMDRkNTM5YzIwODMyYWRiYzhmOTU4M2NkNTczNGE0NA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YWQzNjllOTcyYjAxNDM5NWNhYmI0ZjM0ZmVlMjFlMGE4MWU0ZjIwMDIzNmFi
10
- ZmNmZjY1NDYyMTg5MDYyYjhjZDI5ZjE0MDU5MmI2YjUwYzBjMjg3M2Q1NzVi
11
- MzcxMDFlOWY3MDAwZjM1MGNhMGI3ZDJjZWFjOTg2YmYyMGVjYTE=
9
+ ZTNkMzU1YjhkMjdjNzg0MWFkZDhmNTUzYmU3OGVhZmNlOTBiYjM0NWRiMjRl
10
+ YWRiMTkzNTBiNjY3MDBiODAzOGUxYzk0MDY0YzJiNTUwNGRlNThmMTM0ODg0
11
+ MDc5MGU5MTgxNjQzMWY4ZjQ0MTc2OWQ5MTI3ZjUyNmVjM2ZiZTk=
12
12
  data.tar.gz: !binary |-
13
- YTRmNmQ0YzdmMmRjYWNlOTU5ZGNmZDJjZWNjOTRkZDEyZGNkOGUzOGNjZTRk
14
- MTAyMGE0ZjlmNWU2MDJjOGNjOGVkOTFhMjc4MjM2NGY3NmZhY2JlNzc3OWM5
15
- MWJjZTgwNThjMTg3NjBmNzFjN2ViOGIzYTI5M2VlYzc5MTQzYjk=
13
+ N2ExNzhkZjk0MmM4YTM4ZWQ2YjYwZGVjZTJlMDBiNjVmMGVkYzE1NWVlMDA0
14
+ Y2IwMWFjNjAyMjE1MWE2MDk5ZDY4NWNlODAxMDEyOGNiZjgxMTJlYzg4ZWZk
15
+ ZTE5N2E2ZTFhZTcxZDY0OWJiZjViNzZiOGE0NTNjMTZmNWZlNzY=
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simple_params (1.1.1)
4
+ simple_params (1.1.2)
5
5
  activemodel (>= 3.0, < 5.0)
6
6
  shoulda-matchers (~> 2.8)
7
7
  virtus (>= 1.0.0)
@@ -19,9 +19,16 @@ module SimpleParams
19
19
  end
20
20
 
21
21
  private
22
+ def nested_type
23
+ if options[:type].present? && options[:type].to_sym == :array
24
+ 'Array'
25
+ else
26
+ 'Hash'
27
+ end
28
+ end
22
29
 
23
30
  def nested_description
24
- start = "param :#{name}, Hash, #{description}, #{requirement_description} do"
31
+ start = "param :#{name}, #{nested_type}, #{description}, #{requirement_description} do"
25
32
  attribute_descriptors = []
26
33
  attributes.each { |attribute| attribute_descriptors << attribute.to_s }
27
34
  finish = "end"
@@ -2,22 +2,17 @@ module SimpleParams
2
2
  class ApiPieDoc
3
3
 
4
4
  attr_accessor :base_attributes,
5
- :nested_hashes,
6
- :nested_arrays,
5
+ :nested_classes,
7
6
  :nested_attributes,
8
- :nested_array_attributes,
9
7
  :docs
10
8
 
11
9
  def initialize(simple_params)
12
10
  self.base_attributes = simple_params.defined_attributes
13
- self.nested_hashes = simple_params.nested_hashes
14
- self.nested_arrays = simple_params.nested_arrays
11
+ self.nested_classes = simple_params.nested_classes
15
12
  self.nested_attributes = []
16
- self.nested_array_attributes = []
17
13
  self.docs = []
18
14
 
19
- build_nested_attributes
20
- build_nested_array_attributes
15
+ build_nested_classes
21
16
  end
22
17
 
23
18
  def build
@@ -25,12 +20,8 @@ module SimpleParams
25
20
  docs << Attribute.new(attribute).to_s
26
21
  end
27
22
 
28
- nested_attributes.each do |nested_attribute|
29
- docs << NestedAttribute.new(nested_attribute).to_s
30
- end
31
-
32
- nested_array_attributes.each do |nested_attribute|
33
- docs << NestedArray.new(nested_attribute).to_s
23
+ nested_attributes.each do |nested_class|
24
+ docs << NestedAttribute.new(nested_class).to_s
34
25
  end
35
26
 
36
27
  docs.join("\n")
@@ -38,16 +29,10 @@ module SimpleParams
38
29
 
39
30
  private
40
31
 
41
- def build_nested_attributes
42
- nested_hashes.each do |name, parameter_set|
32
+ def build_nested_classes
33
+ nested_classes.each do |name, parameter_set|
43
34
  nested_attributes << { name => parameter_set.defined_attributes, options: parameter_set.options }
44
35
  end
45
36
  end
46
-
47
- def build_nested_array_attributes
48
- nested_arrays.each do |name, parameter_set|
49
- nested_array_attributes << { name => parameter_set.defined_attributes, options: parameter_set.options }
50
- end
51
- end
52
37
  end
53
38
  end
@@ -3,12 +3,8 @@ require "virtus"
3
3
 
4
4
  module SimpleParams
5
5
  class Attribute
6
- attr_reader :parent
7
- attr_reader :name
8
- attr_reader :type
9
- attr_reader :default
10
- attr_reader :validations
11
- attr_reader :formatter
6
+ attr_reader :parent, :name, :type, :default,
7
+ :validations, :formatter
12
8
 
13
9
  def initialize(parent, name, opts={})
14
10
  @parent = parent
@@ -0,0 +1,68 @@
1
+ module SimpleParams
2
+ module DateTimeHelpers
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ end
7
+
8
+ module ClassMethods
9
+ def define_date_helper_methods(name)
10
+ define_method("#{name}(3i)=") do |day|
11
+ attribute = send("#{name}_attribute")
12
+ value = attribute.send("value") || Date.today
13
+ attribute.send("value=", Date.new(value.year, value.month, day.to_i))
14
+ end
15
+
16
+ define_method("#{name}(2i)=") do |month|
17
+ attribute = send("#{name}_attribute")
18
+ value = attribute.send("value") || Date.today
19
+ attribute.send("value=", Date.new(value.year, month.to_i, value.day))
20
+ end
21
+
22
+ define_method("#{name}(1i)=") do |year|
23
+ attribute = send("#{name}_attribute")
24
+ value = attribute.send("value") || Date.today
25
+ attribute.send("value=", Date.new(year.to_i, value.month, value.day))
26
+ end
27
+ end
28
+
29
+ def define_datetime_helper_methods(name)
30
+ define_method("#{name}(6i)=") do |sec|
31
+ attribute = send("#{name}_attribute")
32
+ value = attribute.send("value") || Time.now.utc
33
+ attribute.send("value=", Time.new(value.year, value.month, value.day, value.hour, value.min, sec.to_i, value.utc_offset))
34
+ end
35
+
36
+ define_method("#{name}(5i)=") do |minute|
37
+ attribute = send("#{name}_attribute")
38
+ value = attribute.send("value") || Time.now.utc
39
+ attribute.send("value=", Time.new(value.year, value.month, value.day, value.hour, minute.to_i, value.sec, value.utc_offset))
40
+ end
41
+
42
+ define_method("#{name}(4i)=") do |hour|
43
+ attribute = send("#{name}_attribute")
44
+ value = attribute.send("value") || Time.now.utc
45
+ attribute.send("value=", Time.new(value.year, value.month, value.day, hour.to_i, value.min, value.sec, value.utc_offset))
46
+ end
47
+
48
+ define_method("#{name}(3i)=") do |day|
49
+ attribute = send("#{name}_attribute")
50
+ value = attribute.send("value") || Time.now.utc
51
+ attribute.send("value=", Time.new(value.year, value.month, day.to_i, value.hour, value.min, value.sec, value.utc_offset))
52
+ end
53
+
54
+ define_method("#{name}(2i)=") do |month|
55
+ attribute = send("#{name}_attribute")
56
+ value = attribute.send("value") || Time.now.utc
57
+ attribute.send("value=", Time.new(value.year, month.to_i, value.day, value.hour, value.min, value.sec, value.utc_offset))
58
+ end
59
+
60
+ define_method("#{name}(1i)=") do |year|
61
+ attribute = send("#{name}_attribute")
62
+ value = attribute.send("value") || Time.now.utc
63
+ attribute.send("value=", Time.new(year.to_i, value.month, value.day, value.hour, value.min, value.sec, value.utc_offset))
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,68 @@
1
+ module SimpleParams
2
+ module HasAttributes
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ def define_attributes(params)
6
+ self.class.defined_attributes.each_pair do |key, opts|
7
+ send("#{key}_attribute=", Attribute.new(self, key, opts))
8
+ end
9
+ end
10
+
11
+ def attributes
12
+ (defined_attributes.keys + nested_classes.keys).flatten
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def defined_attributes
18
+ @define_attributes ||= {}
19
+ end
20
+
21
+ private
22
+ def define_attribute(name, opts = {})
23
+ opts[:type] ||= :string
24
+ defined_attributes[name.to_sym] = opts
25
+ attr_accessor "#{name}_attribute"
26
+
27
+ define_method("#{name}") do
28
+ attribute = send("#{name}_attribute")
29
+ attribute.send("value")
30
+ end
31
+
32
+ define_method("raw_#{name}") do
33
+ attribute = send("#{name}_attribute")
34
+ attribute.send("raw_value")
35
+ end
36
+
37
+ define_method("#{name}=") do |val|
38
+ attribute = send("#{name}_attribute")
39
+ attribute.send("value=", val)
40
+ end
41
+
42
+ if [Date, 'Date', :date].include?(opts[:type])
43
+ define_date_helper_methods(name)
44
+ elsif [DateTime, 'DateTime', :datetime, Time, 'Time', :time].include?(opts[:type])
45
+ define_datetime_helper_methods(name)
46
+ end
47
+ end
48
+
49
+ def add_validations(name, opts = {})
50
+ validations = opts[:validations] || {}
51
+ has_default = opts.has_key?(:default) # checking has_key? because :default may be nil
52
+ optional = opts[:optional]
53
+ if !validations.empty?
54
+ if optional || has_default
55
+ validations.merge!(allow_nil: true)
56
+ else
57
+ validations.merge!(presence: true)
58
+ end
59
+ else
60
+ if !optional && !has_default
61
+ validations.merge!(presence: true)
62
+ end
63
+ end
64
+ validates name, validations unless validations.empty?
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,30 @@
1
+ module SimpleParams
2
+ module HasTypedParams
3
+ extend ActiveSupport::Concern
4
+
5
+ TYPES = [
6
+ :integer,
7
+ :string,
8
+ :decimal,
9
+ :datetime,
10
+ :date,
11
+ :time,
12
+ :float,
13
+ :boolean,
14
+ :array,
15
+ :hash,
16
+ :object
17
+ ]
18
+
19
+ included do
20
+ end
21
+
22
+ module ClassMethods
23
+ TYPES.each do |sym|
24
+ define_method("#{sym}_param") do |name, opts={}|
25
+ param(name, opts.merge(type: sym))
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,27 @@
1
+ module SimpleParams
2
+ module HashHelpers
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+
7
+ private
8
+ def hash_to_symbolized_hash(hash)
9
+ hash.inject({}){|result, (key, value)|
10
+ new_key = case key
11
+ when String then key.to_sym
12
+ else key
13
+ end
14
+ new_value = case value
15
+ when Hash then hash_to_symbolized_hash(value)
16
+ else value
17
+ end
18
+ result[new_key] = new_value
19
+ result
20
+ }
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ require 'active_support/core_ext/string'
2
+
3
+ module SimpleParams
4
+ module RailsHelpers
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ # Required for ActiveModel
8
+ def persisted?; false end
9
+ end
10
+
11
+ module ClassMethods
12
+ def define_rails_helpers(name, klass)
13
+ # E.g. if we have a nested_class named :phones, then we need:
14
+ # - a method called :phones_attributes that also sets :phones
15
+ # - a method called :build_phone
16
+
17
+ define_method("#{name}_attributes=") do |value|
18
+ send("#{name}=", value)
19
+ end
20
+
21
+ singular_key = singularized_key(name)
22
+ define_method("build_#{singular_key}") do |value={}|
23
+ klass.new(value, self)
24
+ end
25
+ end
26
+
27
+ private
28
+ def singularized_key(key)
29
+ key.to_s.singularize
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,68 @@
1
+ module SimpleParams
2
+ module StrictParams
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ def set_strictness
7
+ if self.class.strict_enforcement.nil?
8
+ self.class.strict_enforcement = true
9
+ end
10
+ end
11
+
12
+ # Overriding this method to allow for non-strict enforcement!
13
+ def method_missing(method_name, *arguments, &block)
14
+ if strict_enforcement?
15
+ raise SimpleParamsError, "parameter #{method_name} is not defined."
16
+ else
17
+ if @original_params.include?(method_name.to_sym)
18
+ value = @original_params[method_name.to_sym]
19
+ if value.is_a?(Hash)
20
+ define_anonymous_class(method_name, value)
21
+ else
22
+ Attribute.new(self, method_name).value = value
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ def respond_to?(method_name, include_private = false)
29
+ if strict_enforcement?
30
+ super
31
+ else
32
+ @original_params.include?(method_name.to_sym) || super
33
+ end
34
+ end
35
+
36
+ def define_anonymous_class(name, hash)
37
+ klass_name = name.to_s.split('_').collect(&:capitalize).join
38
+ anonymous_klass = Class.new(Params).tap do |klass|
39
+ if self.class.const_defined?(klass_name)
40
+ begin
41
+ self.class.send(:remove_const, klass_name)
42
+ rescue NameError
43
+ end
44
+ end
45
+ self.class.const_set(klass_name, klass)
46
+ end
47
+ anonymous_klass.allow_undefined_params
48
+ anonymous_klass.new(hash)
49
+ end
50
+
51
+ def strict_enforcement?
52
+ self.class.strict_enforcement
53
+ end
54
+ end
55
+
56
+ module ClassMethods
57
+ attr_accessor :strict_enforcement
58
+
59
+ def strict
60
+ @strict_enforcement = true
61
+ end
62
+
63
+ def allow_undefined_params
64
+ @strict_enforcement = false
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,41 @@
1
+ require "active_model"
2
+
3
+ module SimpleParams
4
+ module Validations
5
+ extend ActiveModel::Validations
6
+
7
+ def valid?(context = nil)
8
+ current_context, self.validation_context = validation_context, context
9
+ errors.clear
10
+ run_validations!
11
+
12
+ # Make sure that nested classes are also valid
13
+ nested_classes_valid? && errors.empty?
14
+ ensure
15
+ self.validation_context = current_context
16
+ end
17
+
18
+ def validate!
19
+ unless valid?
20
+ raise SimpleParamsError, self.errors.to_hash.to_s
21
+ end
22
+ end
23
+
24
+ private
25
+ def nested_classes_valid?
26
+ nested_classes.map do |key, array|
27
+ nested_class_valid?(send("#{key}") )
28
+ end.all?
29
+ end
30
+
31
+ def nested_class_valid?(nested_class)
32
+ if nested_class.is_a?(Array)
33
+ # Have to map? & THEN all?, or else it won't
34
+ # necessarily call valid? on every object
35
+ nested_class.map(&:valid?).all?
36
+ else
37
+ nested_class.valid?
38
+ end
39
+ end
40
+ end
41
+ end