param_param 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61d152a83cea632bd4e660508c5dc62d26231e9bb60a35626e1991548171e205
4
- data.tar.gz: 28d02503d7fc9a374d1e555c3e9328aac9418194ed6520989165b66fe5d4a3cd
3
+ metadata.gz: 8ef6579d2ab3739b51f2987d16d8832e5447a669c1b0fdaebefc052a86ce502d
4
+ data.tar.gz: 331d8721dbdb989c3fa7f01da832d860a34f6207be0a68601651e6ef534685cb
5
5
  SHA512:
6
- metadata.gz: bdef7f585fc8f1050327bcdbe0946cc3255eca321c2f43b17fd42035cdc4d029f5d85011f91e01e2813af50b9e47ae70593f676078e483611efeed2e2a3f583b
7
- data.tar.gz: '004692833ec9cefe0d4ebdc6ec02ffa1c4de71ef38995e03aa62eecf2cbe4e8fa839f75a9119ca4adcab5576742909d69955f332f5e833c01965544fdd54c504'
6
+ metadata.gz: f21bfc4dfcd7fb9e3079aa9776665b408e413af23ceef696e9f06891957b0d7f7a37e8ed21449896db5a8a44ef82c9535c0ceb41a5a7ec00c3f88d8c84f6c6fe
7
+ data.tar.gz: b32827903bd128ea3477162864e39cd83eefebb57d5d08af8d3458b4880e9aab8b2560413a53b6c2d0ea231d40ba40ae0e79b7e03ae90874e59eda5393402bc7
data/README.md CHANGED
@@ -1,4 +1,77 @@
1
1
  # param_param
2
- Params parser built on lambdas.
2
+ Lambda powered pipelines.
3
+ Define pipelines transforming hash values.
3
4
 
4
5
  Inspired by Martin Chabot's [Simple Functional Strong Parameters In Ruby](https://blog.martinosis.com/blog/simple-functional-strong-params-in-ruby) article.
6
+
7
+ # Examples
8
+ ## Validate and transform a user provided data in a web application.
9
+
10
+ ```
11
+ require 'param_param'
12
+ require 'param_param/std'
13
+
14
+ class MyParams
15
+ include ParamParam
16
+ include ParamParam::Std
17
+
18
+ # You can add your own actions
19
+ CAPITALIZED = ->(option) { Success.new(Optiomist.some(option.value.capitalize)) }
20
+ end
21
+
22
+ user_params = MyParams.define do |p|
23
+ {
24
+ name: p::REQUIRED.(p::ALL_OF.([p::STRING, p::MIN_SIZE.(1), p::MAX_SIZE.(50), p::CAPITALIZED])),
25
+ admin: p::REQUIRED.(p::BOOL),
26
+ age: p::OPTIONAL.(p::ALL_OF.([p::INTEGER, p::GT.(0)])),
27
+ }
28
+ end
29
+
30
+ params, errors = user_params.(
31
+ name: 'JOHN',
32
+ admin: '0',
33
+ age: '30',
34
+ race: 'It is not important',
35
+ )
36
+
37
+ params # {:name=>"John", :admin=>false, :age=>30}
38
+ errors # {}
39
+
40
+ params, errors = UserParams.new.process(admin: 'no', age: 'very old')
41
+ params # {:admin=>false}
42
+ errors # {:name=>:missing, :age=>:not_integer}
43
+ ```
44
+
45
+ ## Perform some chain of operations on provided data.
46
+ ```
47
+ require 'param_param'
48
+
49
+ require 'param_param'
50
+
51
+ module Mather
52
+ include ParamParam
53
+
54
+ ADD = ->(value, option) { Success.new(Optiomist.some(option.value + value)) }.curry
55
+ MUL = ->(value, option) { Success.new(Optiomist.some(option.value * value)) }.curry
56
+ SUB = ->(value, option) { Success.new(Optiomist.some(option.value - value)) }.curry
57
+ end
58
+
59
+ rules = Mather.define do |m|
60
+ {
61
+ a: m::ADD.(2),
62
+ b: m::MUL.(2),
63
+ c: m::SUB.(2),
64
+ d: m::ALL_OF.([m::ADD.(2), m::MUL.(2), m::SUB.(2)]),
65
+ }
66
+ end
67
+
68
+ params, errors = rules.(
69
+ a: 10,
70
+ b: 10,
71
+ c: 10,
72
+ d: 10,
73
+ )
74
+
75
+ params # {:a=>12, :b=>20, :c=>8, :d=>22}
76
+ errors # {}
77
+ ```
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ParamParam
4
+ # Defines actions to process hash values.
5
+ #
6
+ # An action is a lambda function assigned to a key.
7
+ # When a hash with values is provied, a value related to a key of the same name as the one the action is assigned to, processes the value.
8
+ #
9
+ # An action needs to be a lambda taking +Optiomist+ option as parameter and returning either:
10
+ # - +ParamParam::Success+ with processed option
11
+ # - +ParamParam::Failure+ with an error
12
+ #
13
+ # Example:
14
+ # actions = Actions.new(
15
+ # key: lambda { |option| option.some? ? Success.new(process(option.value)) : Failure.new(:missing) },
16
+ # ...
17
+ # )
18
+ class Actions
19
+ def initialize(actions)
20
+ @actions = actions
21
+ end
22
+
23
+ # It takes a hash and processes values related to a key by an action assigned to the same key.
24
+ #
25
+ # It returns two hashes:
26
+ # - if a value related to a key can be procesed by an action,
27
+ # the result is bound to the key and added to the first params hash
28
+ # - if a value related to a key can't be processed by an action,
29
+ # the error is bound to the key and added to the last errors hash
30
+ def call(params)
31
+ results = actions.to_h do |key, fn|
32
+ option = params.key?(key) ? optionize(params[key]) : Optiomist.none
33
+ [key, fn.call(option)]
34
+ end
35
+
36
+ errors = results.select { |_, result| result.failure? }
37
+ .transform_values(&:error)
38
+ params = results.select { |_, result| result.success? && result.value.some? }
39
+ .transform_values { |result| result.value.value }
40
+ [params, errors]
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :actions
46
+
47
+ # Converts provided value to +Optiomist::Some+.
48
+ # If the value is already +Optiomist::Some+ or +Optiomist::None+ returns it untouched.
49
+ def optionize(value)
50
+ if value.is_a?(Optiomist::Some) || value.is_a?(Optiomist::None)
51
+ value
52
+ else
53
+ Optiomist.some(value)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,168 +1,133 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # It contains a collection of some useful rules.
4
3
  module ParamParam
5
- # Some string values that can be considered as +true+ (thank you dry-rb for inspiration).
6
- TRUE_VALUES = %w[1 on On ON t true True TRUE T y yes Yes YES Y].freeze
7
- # Some string values that can be considered as +false+ (thank you dry-rb for inspiration).
8
- FALSE_VALUES = %w[0 off Off OFF f false False FALSE F n no No NO N].freeze
9
-
10
- NOT_GTE = :not_gte
11
- NOT_GT = :not_gt
12
- NOT_LTE = :not_lte
13
- NOT_LT = :not_lt
14
- NOT_INCLUDED = :not_included
15
- TOO_LONG = :too_long
16
- TOO_SHORT = :too_short
17
-
18
- NON_BOOL = :non_bool
19
- NON_DECIMAL = :non_decimal
20
- NON_INTEGER = :non_integer
21
- NON_STRING = :non_string
22
-
23
- # Verifies inclusion of a value in a collection.
24
- #
25
- # Returns
26
- # lambda { |collection, option| ... }.
27
- #
28
- # Verifies if value of the +option+ is included in the provided +collection+.
29
- def self.included_in
30
- lambda { |collection, option|
31
- collection.include?(option.value) ? Success.new(option) : Failure.new(NOT_INCLUDED)
32
- }.curry
33
- end
4
+ # It defines some actions that can be useful in an everyday life.
5
+ module Std
6
+ # Some string values that can be considered as +true+ (thank you dry-rb for inspiration).
7
+ TRUE_VALUES = %w[1 on On ON t true True TRUE T y yes Yes YES Y].freeze
8
+ # Some string values that can be considered as +false+ (thank you dry-rb for inspiration).
9
+ FALSE_VALUES = %w[0 off Off OFF f false False FALSE F n no No NO N].freeze
34
10
 
35
- # Returns
36
- # lambda { |limit, option| ... }.
37
- #
38
- # Checks if the +option+'s value is greater than or equal to the provided +limit+.
39
- def self.gte
40
- ->(limit, option) { option.value >= limit ? Success.new(option) : Failure.new(NOT_GTE) }.curry
41
- end
11
+ MISSING_ERR = :missing
42
12
 
43
- # Returns
44
- # lambda { |limit, option| ... }.
45
- #
46
- # Checks if the +option+'s value is greater than the provided +limit+.
47
- def self.gt
48
- ->(limit, option) { option.value > limit ? Success.new(option) : Failure.new(NOT_GT) }.curry
49
- end
13
+ NOT_GTE_ERR = :not_gte
14
+ NOT_GT_ERR = :not_gt
15
+ NOT_LTE_ERR = :not_lte
16
+ NOT_LT_ERR = :not_lt
17
+ NOT_INCLUDED_ERR = :not_included
18
+ TOO_LONG_ERR = :too_long
19
+ TOO_SHORT_ERR = :too_short
50
20
 
51
- # Returns
52
- # lambda { |limit, option| ... }.
53
- #
54
- # Checks if the +option+'s value is less than or equal to the provided +limit+.
55
- def self.lte
56
- ->(limit, option) { option.value <= limit ? Success.new(option) : Failure.new(NOT_LTE) }.curry
57
- end
21
+ NOT_BOOL_ERR = :not_bool
22
+ NOT_DECIMAL_ERR = :not_decimal
23
+ NOT_INTEGER_ERR = :not_integer
24
+ NOT_STRING_ERR = :not_string
58
25
 
59
- # Returns
60
- # lambda { |limit, option| ... }.
61
- #
62
- # Checks if the +option+'s value is less than the provided +limit+.
63
- def self.lt
64
- ->(limit, option) { option.value < limit ? Success.new(option) : Failure.new(NOT_LT) }.curry
65
- end
26
+ # Verifies inclusion of a value in a collection.
27
+ #
28
+ # Verifies if value of the +option+ is included in the provided +collection+.
29
+ INCLUDED_IN = lambda do |collection, option|
30
+ collection.include?(option.value) ? Success.new(option) : Failure.new(NOT_INCLUDED_ERR)
31
+ end.curry
66
32
 
67
- # Returns
68
- # lambda { |limit, option| ... }.
69
- #
70
- # Checks if the size of the value in +option+ does not exceed provided +limit+.
71
- def self.max_size
72
- lambda { |limit, option|
73
- option.value.size <= limit ? Success.new(option) : Failure.new(TOO_LONG)
74
- }.curry
75
- end
33
+ # Describes an optional value.
34
+ #
35
+ # If +option+ is the +Optiomist::None+ it succeeds causing the parameter not to be included in the final result.
36
+ # Otherwise executes the funciton +fn+ for the option.
37
+ OPTIONAL = lambda do |fn, option|
38
+ case option
39
+ in Optiomist::None
40
+ Success.new(option)
41
+ in Optiomist::Some
42
+ fn.call(option)
43
+ end
44
+ end.curry
76
45
 
77
- # Returns
78
- # lambda { |limit, option| ... }.
79
- #
80
- # Checks if the size of the value in +option+ is not lower than the provided +limit+.
81
- def self.min_size
82
- lambda { |limit, option|
83
- option.value.size >= limit ? Success.new(option) : Failure.new(TOO_SHORT)
84
- }.curry
85
- end
46
+ # Describes a required value.
47
+ #
48
+ # It fails if +option+ is a +Optiomist::None+. Otherwise executes the funciton +fn+ for the option.
49
+ REQUIRED = lambda do |fn, option|
50
+ case option
51
+ in Optiomist::None
52
+ Failure.new(MISSING_ERR)
53
+ in Optiomist::Some
54
+ fn.call(option)
55
+ end
56
+ end.curry
86
57
 
87
- # Returns
88
- # lambda { |option| ... }.
89
- #
90
- # Removes leading and trailing spaces from string provided in +option+'s value.
91
- def self.stripped
92
- ->(option) { Success.new(Optiomist.some(option.value.strip)) }
93
- end
58
+ # Checks if the +option+'s value is greater than or equal to the provided +limit+.
59
+ GTE = ->(limit, option) { option.value >= limit ? Success.new(option) : Failure.new(NOT_GTE_ERR) }.curry
60
+
61
+ # Checks if the +option+'s value is greater than the provided +limit+.
62
+ GT = ->(limit, option) { option.value > limit ? Success.new(option) : Failure.new(NOT_GT_ERR) }.curry
63
+
64
+ # Checks if the +option+'s value is less than or equal to the provided +limit+.
65
+ LTE = ->(limit, option) { option.value <= limit ? Success.new(option) : Failure.new(NOT_LTE_ERR) }.curry
66
+
67
+ # Checks if the +option+'s value is less than the provided +limit+.
68
+ LT = ->(limit, option) { option.value < limit ? Success.new(option) : Failure.new(NOT_LT_ERR) }.curry
94
69
 
95
- # Returns
96
- # lambda { |fn, option| ... }.
97
- #
98
- # Converts provided +option+'s value to integer.
99
- # If the conversion is not possible it fails, otherwise executes the provider function +fn+
100
- # for the converted integer value.
101
- def self.integer
102
- lambda { |fn, option|
70
+ # Checks if the size of the value in +option+ does not exceed provided +limit+.
71
+ MAX_SIZE = lambda do |limit, option|
72
+ option.value.size <= limit ? Success.new(option) : Failure.new(TOO_LONG_ERR)
73
+ end.curry
74
+
75
+ # Checks if the size of the value in +option+ is not lower than the provided +limit+.
76
+ MIN_SIZE = lambda do |limit, option|
77
+ option.value.size >= limit ? Success.new(option) : Failure.new(TOO_SHORT_ERR)
78
+ end.curry
79
+
80
+ # Removes leading and trailing spaces from string provided in +option+'s value.
81
+ STRIPPED = ->(option) { Success.new(Optiomist.some(option.value.strip)) }
82
+
83
+ # Converts provided +option+'s value to integer.
84
+ # If the conversion is not possible it fails.
85
+ INTEGER = lambda do |option|
103
86
  begin
104
87
  integer_value = Integer(option.value)
105
88
  rescue StandardError
106
- return Failure.new(NON_INTEGER)
89
+ return Failure.new(NOT_INTEGER_ERR)
107
90
  end
108
- fn.call(Optiomist.some(integer_value))
109
- }.curry
110
- end
91
+ Success.new(Optiomist.some(integer_value))
92
+ end
111
93
 
112
- # Returns
113
- # lambda { |fn, option| ... }.
114
- #
115
- # Converts provided +option+'s value to float.
116
- # If the conversion is not possible it fails, otherwise executes the provider function +fn+
117
- # for the converted float value.
118
- def self.decimal
119
- lambda { |fn, option|
94
+ # Converts provided +option+'s value to float.
95
+ # If the conversion is not possible it fails.
96
+ DECIMAL = lambda do |option|
120
97
  begin
121
98
  float_value = Float(option.value)
122
99
  rescue StandardError
123
- return Failure.new(NON_DECIMAL)
100
+ return Failure.new(NOT_DECIMAL_ERR)
124
101
  end
125
- fn.call(Optiomist.some(float_value))
126
- }.curry
127
- end
102
+ Success.new(Optiomist.some(float_value))
103
+ end
128
104
 
129
- # Returns
130
- # lambda { |fn, option| ... }.
131
- #
132
- # Converts provided +option+'s value to boolean.
133
- # If the conversion is not possible it fails, otherwise executes the provider function +fn+
134
- # for the converted boolean value.
135
- def self.bool
136
- lambda { |fn, option|
105
+ # Converts provided +option+'s value to boolean.
106
+ # If the conversion is not possible it fails.
107
+ BOOL = lambda do |option|
137
108
  case option
138
109
  in Optiomist::Some
139
110
  if [true, *TRUE_VALUES].include?(option.value)
140
- fn.call(Optiomist.some(true))
111
+ Success.new(Optiomist.some(true))
141
112
  elsif [false, *FALSE_VALUES].include?(option.value)
142
- fn.call(Optiomist.some(false))
113
+ Success.new(Optiomist.some(false))
143
114
  else
144
- Failure.new(NON_BOOL)
115
+ Failure.new(NOT_BOOL_ERR)
145
116
  end
146
117
  in Optiomist::None
147
- Failure.new(NON_BOOL)
118
+ Failure.new(NOT_BOOL_ERR)
148
119
  end
149
- }.curry
150
- end
120
+ end
151
121
 
152
- # Returns
153
- # lambda { |fn, option| ... }.
154
- #
155
- # Converts provided +option+'s value to string.
156
- # If the conversion is not possible it fails, otherwise executes the provider function +fn+
157
- # for the converted string value.
158
- def self.string
159
- lambda { |fn, option|
122
+ # Converts provided +option+'s value to string.
123
+ # If the conversion is not possible it fails.
124
+ STRING = lambda do |option|
160
125
  case option
161
126
  in Optiomist::Some
162
- fn.call(Optiomist.some(option.value.to_s))
127
+ Success.new(Optiomist.some(option.value.to_s))
163
128
  in Optiomist::None
164
- Failure.new(NON_STRING)
129
+ Failure.new(NOT_STRING_ERR)
165
130
  end
166
- }.curry
131
+ end
167
132
  end
168
133
  end
data/lib/param_param.rb CHANGED
@@ -2,156 +2,38 @@
2
2
 
3
3
  require 'optiomist'
4
4
  require 'param_param/result'
5
- require 'param_param/std'
5
+ require 'param_param/actions'
6
6
 
7
- # The main purpose of this module is to convert hash data
8
- # applying a chain of rules to values in the provided hash.
7
+ # It allows to define actions that transform hash values.
8
+ # Each actions is bound to a particular key and processes a value related to that key.
9
9
  #
10
- # It can be used to process form data in a web application converting
11
- # user provided data to values understood by the application and validate
12
- # it the data fulfills constraints required by the application.
13
- #
14
- # Example:
15
- #
16
- # class UserOperation
17
- # Rules = ParamParam.define.(
18
- # name: ParamParam.required.(
19
- # ParamParam.string.(ParamParam.all_of.([ParamParam.not_nil, ParamParam.stripped, ParamParam.max_size.(50)]))
20
- # ),
21
- # admin: ParamParam.required.(ParamParam.bool.(ParamParam.any)),
22
- # age: ParamParam.optional.(ParamParam.integer.(ParamParam.gt.(0))),
23
- # )
24
- #
25
- # def create(name:, age:)
26
- # params, errors = Rules.(name: name, age: age)
27
- # throw errors unless errors.empty?
28
- #
29
- # # do something with params
30
- # end
31
- # end
10
+ # Actions could be chained and executed one by one.
11
+ # An actions receives a value from a previous action and is expected to return successful or failed result.
12
+ # A successful result contains a new value being the result of the processing.
13
+ # The new value is passed further in the chain to the next action.
14
+ # A failed result contains a message from an action saying why a particular value can't be processed.
15
+ # Following actions in the chain are not executed.
32
16
  module ParamParam
33
- MISSING = :missing
34
- BLANK = :blank
35
-
36
- # Converts provided value to +Optiomist::Some+.
37
- # If the value is already +Optiomist::Some+ or +Optiomist::None+ returns it untouched.
38
- def self.optionize(value)
39
- if value.is_a?(Optiomist::Some) || value.is_a?(Optiomist::None)
40
- value
41
- else
42
- Optiomist.some(value)
43
- end
44
- end
45
-
46
- # Verifies if provided value is nil, empty string or string consisting only from spaces.
47
- def self.blank?(value)
48
- value.nil? || (value.is_a?(String) && value.strip.empty?)
17
+ def self.included(base)
18
+ base.extend(ClassMethods)
49
19
  end
50
20
 
51
- # Returns lambda that allows defining a set of rules and bind them to symbols.
52
- # Later those rules can be applied to parameters provided in a for of a hash.
53
- # Each rule defined for a given key processes a value related to the same key in provided parameters.
54
- # lambda { |rules, params| ... }
55
- #
56
- # The lambda returns two hashes:
57
- # - if a value related to a key can be procesed by the rules,
58
- # the result is bound to the key and added to the first hash
59
- # - if a rule can't be applied to a value,
60
- # the error is bound to the key and added to the second hash
61
- #
62
- # Each rule needs to be a lambda taking +Optiomist+ as the only or the last parameter and returning either:
63
- # - +ParamParam::Success+ with processed option
64
- # - +ParamParam::Failure+ with an error
65
- def self.define
66
- lambda { |rules, params|
67
- results = rules.to_h do |key, fn|
68
- option = params.key?(key) ? optionize(params[key]) : Optiomist.none
69
- [key, fn.call(option)]
70
- end
71
-
72
- errors = results.select { |_, result| result.failure? }
73
- .transform_values(&:error)
74
- params = results.select { |_, result| result.success? && result.value.some? }
75
- .transform_values { |result| result.value.value }
76
- [params, errors]
77
- }.curry
21
+ module ClassMethods
22
+ def define(&)
23
+ Actions.new(yield(self))
24
+ end
78
25
  end
79
26
 
80
- # It return lambda that allows defining a chain of rules that will be applied one by one
81
- # to value processed by a previous rule.
27
+ # A chain of actions that are executed consecutively
28
+ # and pass a value from a previous action to the following one.
82
29
  #
83
- # Returns:
84
- # lambda { |fns, option| ... }
85
- # If some rule fails the chain is broken and value stops being processed.
86
- def self.all_of
87
- lambda { |fns, option|
30
+ # If some action fails the chain is broken and value stops being processed.
31
+ ALL_OF = lambda do |fns, option|
88
32
  fns.reduce(Success.new(option)) { |result, fn| result.failure? ? result : fn.call(result.value) }
89
- }.curry
90
- end
33
+ end.curry
91
34
 
92
- # Returns
93
- # lambda { |option| ... }.
94
- #
95
35
  # Always succeeds with the provided +option+.
96
- def self.any
97
- ->(option) { Success.new(option) }
98
- end
99
-
100
- # Describes an optional value.
101
- #
102
- # Returns
103
- # lambda { |fn, option| ... }.
104
- #
105
- # If +option+ is the +Optiomist::None+ it succeeds causing the parameter not to be included in the final result.
106
- # Otherwise executes the funciton +fn+ for the option.
107
- def self.optional
108
- lambda { |fn, option|
109
- case option
110
- in Optiomist::None
111
- Success.new(option)
112
- in Optiomist::Some
113
- fn.call(option)
114
- end
115
- }.curry
116
- end
117
-
118
- # Describes a required value.
119
- #
120
- # Returns
121
- # lambda { |fn, option| ... }.
122
- #
123
- # If +option+ is a +Optiomist::None+ it fails otherwise executes the funciton +fn+ for the option.
124
- def self.required
125
- lambda { |fn, option|
126
- case option
127
- in Optiomist::None
128
- Failure.new(MISSING)
129
- in Optiomist::Some
130
- fn.call(option)
131
- end
132
- }.curry
133
- end
134
-
135
- # Converts blank value to nil or passes non blank value to next rule.
136
- #
137
- # Returns
138
- # lambda { |fn, option| ... }.
139
- #
140
- # If provided +option+'s value is blank it succeeds with +nil+
141
- # otherwise executes provided function for the +option+.
142
- def self.blank_to_nil_or
143
- lambda { |fn, option|
144
- blank?(option.value) ? Success.new(Optiomist.some(nil)) : fn.call(option)
145
- }.curry
146
- end
147
-
148
- # Verifies if value is not blank.
149
- #
150
- # Returns
151
- # lambda { |option| ... }.
152
- #
153
- # It fails if provided +option+ is blank, otherwise succeeds with the +option+.
154
- def self.not_blank
155
- ->(option) { blank?(option.value) ? Failure.new(BLANK) : Success.new(option) }
36
+ ANY = lambda do |option|
37
+ Success.new(option)
156
38
  end
157
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: param_param
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michał Radmacher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-11 00:00:00.000000000 Z
11
+ date: 2024-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: optiomist
@@ -35,6 +35,7 @@ files:
35
35
  - LICENSE
36
36
  - README.md
37
37
  - lib/param_param.rb
38
+ - lib/param_param/actions.rb
38
39
  - lib/param_param/result.rb
39
40
  - lib/param_param/std.rb
40
41
  homepage: https://github.com/mradmacher/param_param
@@ -57,8 +58,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
58
  - !ruby/object:Gem::Version
58
59
  version: '0'
59
60
  requirements: []
60
- rubygems_version: 3.3.7
61
+ rubygems_version: 3.4.10
61
62
  signing_key:
62
63
  specification_version: 4
63
- summary: Params parser built on lambdas
64
+ summary: Lambda powered processing of hash values
64
65
  test_files: []