params_ready_rails5 0.0.7
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.
- checksums.yaml +7 -0
- data/lib/arel/cte_name.rb +20 -0
- data/lib/params_ready/builder.rb +161 -0
- data/lib/params_ready/error.rb +31 -0
- data/lib/params_ready/extensions/class_reader_writer.rb +33 -0
- data/lib/params_ready/extensions/collection.rb +43 -0
- data/lib/params_ready/extensions/delegation.rb +25 -0
- data/lib/params_ready/extensions/finalizer.rb +26 -0
- data/lib/params_ready/extensions/freezer.rb +49 -0
- data/lib/params_ready/extensions/hash.rb +46 -0
- data/lib/params_ready/extensions/late_init.rb +38 -0
- data/lib/params_ready/extensions/registry.rb +44 -0
- data/lib/params_ready/extensions/undefined.rb +23 -0
- data/lib/params_ready/format.rb +132 -0
- data/lib/params_ready/helpers/arel_builder.rb +68 -0
- data/lib/params_ready/helpers/callable.rb +14 -0
- data/lib/params_ready/helpers/conditional_block.rb +31 -0
- data/lib/params_ready/helpers/find_in_hash.rb +22 -0
- data/lib/params_ready/helpers/interface_definer.rb +48 -0
- data/lib/params_ready/helpers/key_map.rb +176 -0
- data/lib/params_ready/helpers/memo.rb +41 -0
- data/lib/params_ready/helpers/options.rb +107 -0
- data/lib/params_ready/helpers/parameter_definer_class_methods.rb +39 -0
- data/lib/params_ready/helpers/parameter_storage_class_methods.rb +63 -0
- data/lib/params_ready/helpers/parameter_user_class_methods.rb +35 -0
- data/lib/params_ready/helpers/relation_builder_wrapper.rb +35 -0
- data/lib/params_ready/helpers/rule.rb +76 -0
- data/lib/params_ready/helpers/storage.rb +30 -0
- data/lib/params_ready/helpers/usage_rule.rb +36 -0
- data/lib/params_ready/input_context.rb +31 -0
- data/lib/params_ready/intent.rb +70 -0
- data/lib/params_ready/marshaller/array_marshallers.rb +132 -0
- data/lib/params_ready/marshaller/builder_module.rb +9 -0
- data/lib/params_ready/marshaller/collection.rb +165 -0
- data/lib/params_ready/marshaller/definition_module.rb +63 -0
- data/lib/params_ready/marshaller/enum_set_marshallers.rb +96 -0
- data/lib/params_ready/marshaller/parameter_module.rb +11 -0
- data/lib/params_ready/marshaller/polymorph_marshallers.rb +67 -0
- data/lib/params_ready/marshaller/struct_marshallers.rb +100 -0
- data/lib/params_ready/marshaller/tuple_marshallers.rb +103 -0
- data/lib/params_ready/ordering/column.rb +60 -0
- data/lib/params_ready/ordering/ordering.rb +276 -0
- data/lib/params_ready/output_parameters.rb +138 -0
- data/lib/params_ready/pagination/abstract_pagination.rb +18 -0
- data/lib/params_ready/pagination/cursor.rb +171 -0
- data/lib/params_ready/pagination/direction.rb +148 -0
- data/lib/params_ready/pagination/keyset_pagination.rb +254 -0
- data/lib/params_ready/pagination/keysets.rb +70 -0
- data/lib/params_ready/pagination/nulls.rb +31 -0
- data/lib/params_ready/pagination/offset_pagination.rb +130 -0
- data/lib/params_ready/pagination/tendency.rb +28 -0
- data/lib/params_ready/parameter/abstract_struct_parameter.rb +204 -0
- data/lib/params_ready/parameter/array_parameter.rb +197 -0
- data/lib/params_ready/parameter/definition.rb +272 -0
- data/lib/params_ready/parameter/enum_set_parameter.rb +102 -0
- data/lib/params_ready/parameter/parameter.rb +475 -0
- data/lib/params_ready/parameter/polymorph_parameter.rb +172 -0
- data/lib/params_ready/parameter/state.rb +132 -0
- data/lib/params_ready/parameter/struct_parameter.rb +64 -0
- data/lib/params_ready/parameter/tuple_parameter.rb +152 -0
- data/lib/params_ready/parameter/value_parameter.rb +186 -0
- data/lib/params_ready/parameter_definer.rb +14 -0
- data/lib/params_ready/parameter_user.rb +35 -0
- data/lib/params_ready/query/array_grouping.rb +68 -0
- data/lib/params_ready/query/custom_predicate.rb +102 -0
- data/lib/params_ready/query/exists_predicate.rb +103 -0
- data/lib/params_ready/query/fixed_operator_predicate.rb +77 -0
- data/lib/params_ready/query/grouping.rb +177 -0
- data/lib/params_ready/query/join_clause.rb +87 -0
- data/lib/params_ready/query/nullness_predicate.rb +71 -0
- data/lib/params_ready/query/polymorph_predicate.rb +77 -0
- data/lib/params_ready/query/predicate.rb +203 -0
- data/lib/params_ready/query/predicate_operator.rb +132 -0
- data/lib/params_ready/query/relation.rb +337 -0
- data/lib/params_ready/query/structured_grouping.rb +58 -0
- data/lib/params_ready/query/variable_operator_predicate.rb +125 -0
- data/lib/params_ready/query_context.rb +21 -0
- data/lib/params_ready/restriction.rb +252 -0
- data/lib/params_ready/result.rb +109 -0
- data/lib/params_ready/value/coder.rb +210 -0
- data/lib/params_ready/value/constraint.rb +198 -0
- data/lib/params_ready/value/custom.rb +56 -0
- data/lib/params_ready/value/validator.rb +81 -0
- data/lib/params_ready/version.rb +7 -0
- data/lib/params_ready.rb +28 -0
- metadata +227 -0
@@ -0,0 +1,252 @@
|
|
1
|
+
module ParamsReady
|
2
|
+
class Restriction
|
3
|
+
module Wrapper
|
4
|
+
extend Forwardable
|
5
|
+
attr_reader :restriction
|
6
|
+
def_delegators :restriction, :name_permitted?, :permitted?, :permissions_for
|
7
|
+
|
8
|
+
def delegate(*args)
|
9
|
+
return self if @restriction.everything?
|
10
|
+
|
11
|
+
new_restriction = @restriction.delegate(*args)
|
12
|
+
clone(restriction: new_restriction)
|
13
|
+
end
|
14
|
+
|
15
|
+
def for_children(parameter)
|
16
|
+
return self if @restriction.everything?
|
17
|
+
|
18
|
+
new_restriction = @restriction.for_children parameter
|
19
|
+
clone(restriction: new_restriction)
|
20
|
+
end
|
21
|
+
|
22
|
+
def permit_all
|
23
|
+
return self if @restriction.everything?
|
24
|
+
|
25
|
+
clone(restriction: Restriction.blanket_permission)
|
26
|
+
end
|
27
|
+
|
28
|
+
def permit(*list)
|
29
|
+
restriction = Restriction.permit(*list)
|
30
|
+
return self if @restriction.everything? && restriction.everything?
|
31
|
+
|
32
|
+
clone(restriction: restriction)
|
33
|
+
end
|
34
|
+
|
35
|
+
def prohibit(*list)
|
36
|
+
restriction = Restriction.prohibit(*list)
|
37
|
+
return self if @restriction.everything? && restriction.everything?
|
38
|
+
|
39
|
+
clone(restriction: restriction)
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_restriction
|
43
|
+
@restriction
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Everything
|
48
|
+
def self.key?(_)
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.[](_)
|
53
|
+
Everything
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.dup
|
57
|
+
self
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class Nothing
|
62
|
+
def self.key?(_)
|
63
|
+
false
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.[](_)
|
67
|
+
Nothing
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.dup
|
71
|
+
self
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.blanket_permission
|
76
|
+
@blanket_permission ||= Allowlist.new
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.permit(*args)
|
80
|
+
Allowlist.instance(*args)
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.prohibit(*args)
|
84
|
+
Denylist.instance(*args)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.from_array(arr)
|
88
|
+
arr.each_with_object({}) do |element, restriction|
|
89
|
+
case element
|
90
|
+
when String, Symbol
|
91
|
+
restriction[element.to_sym] = Everything
|
92
|
+
when Hash
|
93
|
+
element.each do |key, value|
|
94
|
+
restriction[key.to_sym] = value
|
95
|
+
end
|
96
|
+
else
|
97
|
+
raise TypeError.new("Unexpected as restriction item: #{element}")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.instance(*list)
|
103
|
+
return blanket_permission if list.length == 1 && list[0] == default
|
104
|
+
|
105
|
+
restriction_list = if list.length == 1 && list[0].is_a?(Regexp)
|
106
|
+
list[0]
|
107
|
+
else
|
108
|
+
from_array(list)
|
109
|
+
end
|
110
|
+
new restriction_list
|
111
|
+
end
|
112
|
+
|
113
|
+
attr_reader :restriction
|
114
|
+
|
115
|
+
def initialize(restriction = self.class.default)
|
116
|
+
@restriction = if restriction.is_a? self.class
|
117
|
+
restriction.restriction
|
118
|
+
else
|
119
|
+
restriction.freeze
|
120
|
+
end
|
121
|
+
freeze
|
122
|
+
end
|
123
|
+
|
124
|
+
def hash
|
125
|
+
@restriction.hash
|
126
|
+
end
|
127
|
+
|
128
|
+
def everything?
|
129
|
+
@restriction == self.class.default
|
130
|
+
end
|
131
|
+
|
132
|
+
def name_listed?(name)
|
133
|
+
if @restriction.is_a? Regexp
|
134
|
+
name =~ @restriction
|
135
|
+
else
|
136
|
+
@restriction.key?(name)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def permitted?(parameter)
|
141
|
+
name = parameter.name
|
142
|
+
return false unless name_permitted?(name)
|
143
|
+
return true unless parameter.respond_to? :permission_depends_on
|
144
|
+
|
145
|
+
children = parameter.permission_depends_on
|
146
|
+
intent = parameter.intent_for_children(self)
|
147
|
+
children.all? do |child|
|
148
|
+
intent.permitted?(child)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def delegate(parent, delegate_name, *others)
|
153
|
+
return self if everything?
|
154
|
+
|
155
|
+
list = restriction_list_for(parent)
|
156
|
+
|
157
|
+
self.class.instance({ delegate_name => list }, *others)
|
158
|
+
end
|
159
|
+
|
160
|
+
def for_children(parameter)
|
161
|
+
return self if everything?
|
162
|
+
|
163
|
+
list = restriction_list_for(parameter)
|
164
|
+
if list.is_a? Restriction
|
165
|
+
list
|
166
|
+
else
|
167
|
+
self.class.instance(*list)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def restriction_list_for(parameter)
|
172
|
+
name = parameter.name
|
173
|
+
raise ParamsReadyError, "Parameter '#{name}' not permitted" unless name_permitted? name
|
174
|
+
restriction_list_for_name(name)
|
175
|
+
end
|
176
|
+
|
177
|
+
def to_restriction
|
178
|
+
self
|
179
|
+
end
|
180
|
+
|
181
|
+
def permit_all
|
182
|
+
self.class.permit_all
|
183
|
+
end
|
184
|
+
|
185
|
+
def self.permit_all
|
186
|
+
new default
|
187
|
+
end
|
188
|
+
|
189
|
+
class Allowlist < Restriction
|
190
|
+
def self.default
|
191
|
+
Everything
|
192
|
+
end
|
193
|
+
|
194
|
+
def name_permitted?(name)
|
195
|
+
name_listed?(name)
|
196
|
+
end
|
197
|
+
|
198
|
+
def permit(*args)
|
199
|
+
self.class.permit(*args)
|
200
|
+
end
|
201
|
+
|
202
|
+
def ==(other)
|
203
|
+
return false unless other.is_a? self.class
|
204
|
+
return true if object_id == other.object_id
|
205
|
+
|
206
|
+
restriction == other.restriction
|
207
|
+
end
|
208
|
+
|
209
|
+
protected
|
210
|
+
|
211
|
+
def restriction_list_for_name(name)
|
212
|
+
if @restriction.is_a? Regexp
|
213
|
+
self.class.default
|
214
|
+
else
|
215
|
+
@restriction[name]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
class Denylist < Restriction
|
221
|
+
def self.default
|
222
|
+
Nothing
|
223
|
+
end
|
224
|
+
|
225
|
+
def name_permitted?(name)
|
226
|
+
return true unless name_listed?(name)
|
227
|
+
return false unless @restriction.is_a?(Hash)
|
228
|
+
return true if @restriction[name].is_a?(Array)
|
229
|
+
return true if @restriction[name].is_a?(Symbol)
|
230
|
+
return true if @restriction[name] == self.class.default
|
231
|
+
|
232
|
+
false
|
233
|
+
end
|
234
|
+
|
235
|
+
def prohibit(*args)
|
236
|
+
self.class.prohibit(*args)
|
237
|
+
end
|
238
|
+
|
239
|
+
protected
|
240
|
+
|
241
|
+
def restriction_list_for_name(name)
|
242
|
+
if @restriction.is_a? Regexp
|
243
|
+
self.class.default
|
244
|
+
elsif @restriction[name].nil?
|
245
|
+
self.class.default
|
246
|
+
else
|
247
|
+
@restriction[name]
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require_relative 'error'
|
2
|
+
|
3
|
+
module ParamsReady
|
4
|
+
class AbstractReporter
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(name)
|
8
|
+
@name = name.to_s.freeze
|
9
|
+
end
|
10
|
+
|
11
|
+
def error!(err)
|
12
|
+
report_error(nil, err)
|
13
|
+
end
|
14
|
+
|
15
|
+
def full_path(path)
|
16
|
+
return [name] if path.nil? || path.empty?
|
17
|
+
[name, *path]
|
18
|
+
end
|
19
|
+
|
20
|
+
def for_child(name)
|
21
|
+
Reporter.new name, self
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Result < AbstractReporter
|
26
|
+
class Error < ParamsReadyError; end
|
27
|
+
|
28
|
+
def initialize(name)
|
29
|
+
super
|
30
|
+
@errors = []
|
31
|
+
@children = {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def full_scope(scope)
|
35
|
+
return name if scope.empty?
|
36
|
+
|
37
|
+
"#{scope}.#{name}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def errors(scope = '')
|
41
|
+
scope = full_scope(scope)
|
42
|
+
proper = @errors.empty? ? {} : { scope => @errors }
|
43
|
+
@children.values.reduce(proper) do |result, child|
|
44
|
+
result.merge(child.errors(scope))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def report_error(path, err)
|
49
|
+
raise ParamsReadyError, "Is not Error: #{err}" unless err.is_a? StandardError
|
50
|
+
|
51
|
+
name, *path = path
|
52
|
+
if name.nil?
|
53
|
+
@errors << err
|
54
|
+
else
|
55
|
+
@children[name] ||= Result.new(name)
|
56
|
+
@children[name].report_error(path, err)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def ok?
|
61
|
+
return false unless @errors.empty?
|
62
|
+
|
63
|
+
@children.values.all? do |child|
|
64
|
+
child.ok?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def child_ok?(path)
|
69
|
+
name, *path = path
|
70
|
+
return ok? if name.nil?
|
71
|
+
return true unless @children.key? name
|
72
|
+
|
73
|
+
@children[name].child_ok?(path)
|
74
|
+
end
|
75
|
+
|
76
|
+
def error
|
77
|
+
return nil if ok?
|
78
|
+
|
79
|
+
Result::Error.new(error_messages(' -- '))
|
80
|
+
end
|
81
|
+
|
82
|
+
def error_messages(separator = "\n")
|
83
|
+
errors.flat_map do |scope, errors|
|
84
|
+
["errors for #{scope}"] + errors.map { |err| err.message }
|
85
|
+
end.join(separator)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Reporter < AbstractReporter
|
90
|
+
attr_reader :name
|
91
|
+
|
92
|
+
def initialize(name, parent)
|
93
|
+
super name
|
94
|
+
@parent = parent
|
95
|
+
end
|
96
|
+
|
97
|
+
def ok?
|
98
|
+
child_ok?(nil)
|
99
|
+
end
|
100
|
+
|
101
|
+
def child_ok?(path)
|
102
|
+
@parent.child_ok?(full_path(path))
|
103
|
+
end
|
104
|
+
|
105
|
+
def report_error(path, err)
|
106
|
+
@parent.report_error(full_path(path), err)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'date'
|
2
|
+
require_relative '../error'
|
3
|
+
require_relative '../extensions/late_init'
|
4
|
+
require_relative '../extensions/finalizer'
|
5
|
+
require_relative '../extensions/class_reader_writer'
|
6
|
+
|
7
|
+
module ParamsReady
|
8
|
+
module Value
|
9
|
+
module Coercion
|
10
|
+
def try_coerce(input, context)
|
11
|
+
coerce input, context
|
12
|
+
rescue => _error
|
13
|
+
raise CoercionError.new(input, value_class_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def strict_default?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class AbstractCoder
|
22
|
+
extend Extensions::ClassReaderWriter
|
23
|
+
|
24
|
+
def self.value_class_name
|
25
|
+
last = self.name.split("::").last
|
26
|
+
last.remove('Coder')
|
27
|
+
end
|
28
|
+
|
29
|
+
class_reader_writer :type_identifier
|
30
|
+
type_identifier :value
|
31
|
+
end
|
32
|
+
|
33
|
+
class Coder < AbstractCoder
|
34
|
+
extend Coercion
|
35
|
+
|
36
|
+
def self.instance(**opts)
|
37
|
+
raise ParamsReadyError, "No options expected, got: #{opts}" unless opts.empty?
|
38
|
+
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
class Instantiable < AbstractCoder
|
43
|
+
include Coercion
|
44
|
+
|
45
|
+
def self.instance(**opts)
|
46
|
+
new **opts
|
47
|
+
end
|
48
|
+
|
49
|
+
def type_identifier
|
50
|
+
self.class.type_identifier
|
51
|
+
end
|
52
|
+
|
53
|
+
def strict_default?
|
54
|
+
self.class.strict_default?
|
55
|
+
end
|
56
|
+
|
57
|
+
def value_class_name
|
58
|
+
self.class.value_class_name
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class GenericCoder
|
64
|
+
extend Extensions::LateInit
|
65
|
+
extend Extensions::Finalizer
|
66
|
+
include Extensions::Finalizer::InstanceMethods
|
67
|
+
include Coercion
|
68
|
+
|
69
|
+
def initialize(name)
|
70
|
+
@name = name
|
71
|
+
@coerce = nil
|
72
|
+
@format = nil
|
73
|
+
@type_identifier = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
late_init(:coerce, getter: false)
|
77
|
+
late_init(:format, getter: false)
|
78
|
+
late_init(:type_identifier, obligatory: false)
|
79
|
+
|
80
|
+
def value_class_name
|
81
|
+
@name
|
82
|
+
end
|
83
|
+
|
84
|
+
def coerce(input, context)
|
85
|
+
@coerce[input, context]
|
86
|
+
end
|
87
|
+
|
88
|
+
def format(value, format)
|
89
|
+
@format[value, format]
|
90
|
+
end
|
91
|
+
|
92
|
+
def finish
|
93
|
+
super
|
94
|
+
freeze
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class IntegerCoder < Coder
|
99
|
+
type_identifier :number
|
100
|
+
|
101
|
+
def self.coerce(input, _)
|
102
|
+
return nil if input.nil? || input == ''
|
103
|
+
Integer(input)
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.format(value, format)
|
107
|
+
value.to_s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class DecimalCoder < Coder
|
112
|
+
type_identifier :number
|
113
|
+
|
114
|
+
def self.coerce(input, _)
|
115
|
+
return nil if input.nil? || input == ''
|
116
|
+
BigDecimal(input)
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.format(value, format)
|
120
|
+
value.to_s('F')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class BooleanCoder < Coder
|
125
|
+
type_identifier :boolean
|
126
|
+
|
127
|
+
def self.coerce(input, _)
|
128
|
+
return nil if input.nil? || input == ''
|
129
|
+
return input if input.is_a?(TrueClass) || input.is_a?(FalseClass)
|
130
|
+
str = input.to_s
|
131
|
+
case str
|
132
|
+
when 'true', 'TRUE', 't', 'T', '1'
|
133
|
+
true
|
134
|
+
when 'false', 'FALSE', 'f', 'F', '0'
|
135
|
+
false
|
136
|
+
else
|
137
|
+
raise
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.format(value, format)
|
142
|
+
value.to_s
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class StringCoder < Coder
|
147
|
+
def self.coerce(input, _)
|
148
|
+
input.to_s
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.format(value, _)
|
152
|
+
value
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class SymbolCoder < Coder
|
157
|
+
type_identifier :symbol
|
158
|
+
|
159
|
+
def self.coerce(input, _)
|
160
|
+
input.to_sym
|
161
|
+
end
|
162
|
+
|
163
|
+
def self.format(value, format)
|
164
|
+
value.to_s
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class DateCoder < Coder
|
169
|
+
type_identifier :date
|
170
|
+
|
171
|
+
def self.coerce(input, _)
|
172
|
+
return nil if input.nil? || input == ''
|
173
|
+
if input.is_a?(Numeric)
|
174
|
+
Time.at(input).to_date
|
175
|
+
elsif input.is_a?(String)
|
176
|
+
Date.parse(input)
|
177
|
+
elsif input.respond_to?(:to_date)
|
178
|
+
input.to_date
|
179
|
+
else
|
180
|
+
raise ParamsReadyError, "Unimplemented for type #{input.class.name}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.format(value, format)
|
185
|
+
value.to_s
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
class DateTimeCoder < Coder
|
190
|
+
type_identifier :date
|
191
|
+
|
192
|
+
def self.coerce(input, _)
|
193
|
+
return nil if input.nil? || input == ''
|
194
|
+
if input.is_a?(Numeric)
|
195
|
+
Time.at(input).to_datetime
|
196
|
+
elsif input.is_a?(String)
|
197
|
+
DateTime.parse(input)
|
198
|
+
elsif input.respond_to?(:to_datetime)
|
199
|
+
input.to_datetime
|
200
|
+
else
|
201
|
+
raise ParamsReadyError, "Unimplemented for type #{input.class.name}"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.format(value, format)
|
206
|
+
value.to_s
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|