super-smart-tool 0.0.1

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 (63) hide show
  1. checksums.yaml +7 -0
  2. data/dry-types-1.9.1/CHANGELOG.md +1145 -0
  3. data/dry-types-1.9.1/LICENSE +20 -0
  4. data/dry-types-1.9.1/README.md +17 -0
  5. data/dry-types-1.9.1/dry-types.gemspec +45 -0
  6. data/dry-types-1.9.1/lib/dry/types/any.rb +41 -0
  7. data/dry-types-1.9.1/lib/dry/types/array/constructor.rb +24 -0
  8. data/dry-types-1.9.1/lib/dry/types/array/member.rb +118 -0
  9. data/dry-types-1.9.1/lib/dry/types/array.rb +32 -0
  10. data/dry-types-1.9.1/lib/dry/types/builder.rb +221 -0
  11. data/dry-types-1.9.1/lib/dry/types/builder_methods.rb +138 -0
  12. data/dry-types-1.9.1/lib/dry/types/coercions/json.rb +57 -0
  13. data/dry-types-1.9.1/lib/dry/types/coercions/params.rb +168 -0
  14. data/dry-types-1.9.1/lib/dry/types/coercions.rb +105 -0
  15. data/dry-types-1.9.1/lib/dry/types/compat.rb +1 -0
  16. data/dry-types-1.9.1/lib/dry/types/compiler.rb +138 -0
  17. data/dry-types-1.9.1/lib/dry/types/composition.rb +138 -0
  18. data/dry-types-1.9.1/lib/dry/types/constrained/coercible.rb +59 -0
  19. data/dry-types-1.9.1/lib/dry/types/constrained.rb +146 -0
  20. data/dry-types-1.9.1/lib/dry/types/constraints.rb +30 -0
  21. data/dry-types-1.9.1/lib/dry/types/constructor/function.rb +203 -0
  22. data/dry-types-1.9.1/lib/dry/types/constructor/wrapper.rb +88 -0
  23. data/dry-types-1.9.1/lib/dry/types/constructor.rb +195 -0
  24. data/dry-types-1.9.1/lib/dry/types/container.rb +12 -0
  25. data/dry-types-1.9.1/lib/dry/types/core.rb +106 -0
  26. data/dry-types-1.9.1/lib/dry/types/decorator.rb +94 -0
  27. data/dry-types-1.9.1/lib/dry/types/default.rb +122 -0
  28. data/dry-types-1.9.1/lib/dry/types/enum.rb +121 -0
  29. data/dry-types-1.9.1/lib/dry/types/errors.rb +138 -0
  30. data/dry-types-1.9.1/lib/dry/types/extensions/maybe.rb +128 -0
  31. data/dry-types-1.9.1/lib/dry/types/extensions/monads.rb +34 -0
  32. data/dry-types-1.9.1/lib/dry/types/extensions.rb +9 -0
  33. data/dry-types-1.9.1/lib/dry/types/fn_container.rb +37 -0
  34. data/dry-types-1.9.1/lib/dry/types/hash/constructor.rb +25 -0
  35. data/dry-types-1.9.1/lib/dry/types/hash.rb +134 -0
  36. data/dry-types-1.9.1/lib/dry/types/implication.rb +64 -0
  37. data/dry-types-1.9.1/lib/dry/types/inflector.rb +9 -0
  38. data/dry-types-1.9.1/lib/dry/types/intersection.rb +102 -0
  39. data/dry-types-1.9.1/lib/dry/types/json.rb +35 -0
  40. data/dry-types-1.9.1/lib/dry/types/lax.rb +66 -0
  41. data/dry-types-1.9.1/lib/dry/types/map.rb +134 -0
  42. data/dry-types-1.9.1/lib/dry/types/meta.rb +53 -0
  43. data/dry-types-1.9.1/lib/dry/types/module.rb +127 -0
  44. data/dry-types-1.9.1/lib/dry/types/nominal.rb +201 -0
  45. data/dry-types-1.9.1/lib/dry/types/options.rb +34 -0
  46. data/dry-types-1.9.1/lib/dry/types/params.rb +38 -0
  47. data/dry-types-1.9.1/lib/dry/types/predicate_inferrer.rb +235 -0
  48. data/dry-types-1.9.1/lib/dry/types/predicate_registry.rb +32 -0
  49. data/dry-types-1.9.1/lib/dry/types/primitive_inferrer.rb +75 -0
  50. data/dry-types-1.9.1/lib/dry/types/printable.rb +14 -0
  51. data/dry-types-1.9.1/lib/dry/types/printer/composition.rb +44 -0
  52. data/dry-types-1.9.1/lib/dry/types/printer.rb +313 -0
  53. data/dry-types-1.9.1/lib/dry/types/result.rb +72 -0
  54. data/dry-types-1.9.1/lib/dry/types/schema/key.rb +138 -0
  55. data/dry-types-1.9.1/lib/dry/types/schema.rb +408 -0
  56. data/dry-types-1.9.1/lib/dry/types/spec/types.rb +164 -0
  57. data/dry-types-1.9.1/lib/dry/types/sum.rb +105 -0
  58. data/dry-types-1.9.1/lib/dry/types/type.rb +53 -0
  59. data/dry-types-1.9.1/lib/dry/types/version.rb +7 -0
  60. data/dry-types-1.9.1/lib/dry/types.rb +259 -0
  61. data/dry-types-1.9.1/lib/dry-types.rb +3 -0
  62. data/super-smart-tool.gemspec +11 -0
  63. metadata +101 -0
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "bigdecimal"
5
+ require "bigdecimal/util"
6
+ require "time"
7
+
8
+ module Dry
9
+ module Types
10
+ module Coercions
11
+ # JSON-specific coercions
12
+ #
13
+ # @api public
14
+ module JSON
15
+ extend Coercions
16
+
17
+ # @param [Object] input
18
+ #
19
+ # @return [nil] if the input is nil
20
+ #
21
+ # @raise CoercionError
22
+ #
23
+ # @api public
24
+ def self.to_nil(input, &)
25
+ if input.nil?
26
+ nil
27
+ elsif block_given?
28
+ yield
29
+ else
30
+ raise CoercionError, "#{input.inspect} is not nil"
31
+ end
32
+ end
33
+
34
+ # @param [#to_d, Object] input
35
+ #
36
+ # @return [BigDecimal,nil]
37
+ #
38
+ # @raise CoercionError
39
+ #
40
+ # @api public
41
+ def self.to_decimal(input, &)
42
+ if input.is_a?(::Float)
43
+ input.to_d
44
+ else
45
+ BigDecimal(input)
46
+ end
47
+ rescue ::ArgumentError, ::TypeError
48
+ if block_given?
49
+ yield
50
+ else
51
+ raise CoercionError, "#{input} cannot be coerced to decimal"
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "bigdecimal/util"
5
+
6
+ module Dry
7
+ module Types
8
+ module Coercions
9
+ # Params-specific coercions
10
+ #
11
+ # @api public
12
+ module Params
13
+ TRUE_VALUES = %w[1 on On ON t true True TRUE T y yes Yes YES Y].freeze
14
+ FALSE_VALUES = %w[0 off Off OFF f false False FALSE F n no No NO N].freeze
15
+ BOOLEAN_MAP = EMPTY_HASH.merge(
16
+ [true, *TRUE_VALUES].to_h { |v| [v, true] },
17
+ [false, *FALSE_VALUES].to_h { |v| [v, false] }
18
+ ).freeze
19
+
20
+ extend Coercions
21
+
22
+ # @param [Object] input
23
+ #
24
+ # @return [nil] if the input is an empty string or nil
25
+ #
26
+ # @raise CoercionError
27
+ #
28
+ # @api public
29
+ def self.to_nil(input, &)
30
+ if input.nil? || empty_str?(input)
31
+ nil
32
+ elsif block_given?
33
+ yield
34
+ else
35
+ raise CoercionError, "#{input.inspect} is not nil"
36
+ end
37
+ end
38
+
39
+ # @param [String, Object] input
40
+ #
41
+ # @return [Boolean,Object]
42
+ #
43
+ # @see TRUE_VALUES
44
+ # @see FALSE_VALUES
45
+ #
46
+ # @raise CoercionError
47
+ #
48
+ # @api public
49
+ def self.to_true(input, &)
50
+ BOOLEAN_MAP.fetch(input.to_s) do
51
+ if block_given?
52
+ yield
53
+ else
54
+ raise CoercionError, "#{input} cannot be coerced to true"
55
+ end
56
+ end
57
+ end
58
+
59
+ # @param [String, Object] input
60
+ #
61
+ # @return [Boolean,Object]
62
+ #
63
+ # @see TRUE_VALUES
64
+ # @see FALSE_VALUES
65
+ #
66
+ # @raise CoercionError
67
+ #
68
+ # @api public
69
+ def self.to_false(input, &)
70
+ BOOLEAN_MAP.fetch(input.to_s) do
71
+ if block_given?
72
+ yield
73
+ else
74
+ raise CoercionError, "#{input} cannot be coerced to false"
75
+ end
76
+ end
77
+ end
78
+
79
+ # @param [#to_int, #to_i, Object] input
80
+ #
81
+ # @return [Integer, nil, Object]
82
+ #
83
+ # @raise CoercionError
84
+ #
85
+ # @api public
86
+ def self.to_int(input, &)
87
+ if input.is_a?(::String)
88
+ Integer(input, 10)
89
+ else
90
+ Integer(input)
91
+ end
92
+ rescue ::ArgumentError, ::TypeError => exception
93
+ CoercionError.handle(exception, &)
94
+ end
95
+
96
+ # @param [#to_f, Object] input
97
+ #
98
+ # @return [Float, nil, Object]
99
+ #
100
+ # @raise CoercionError
101
+ #
102
+ # @api public
103
+ def self.to_float(input, &)
104
+ Float(input)
105
+ rescue ::ArgumentError, ::TypeError => exception
106
+ CoercionError.handle(exception, &)
107
+ end
108
+
109
+ # @param [#to_d, Object] input
110
+ #
111
+ # @return [BigDecimal, nil, Object]
112
+ #
113
+ # @raise CoercionError
114
+ #
115
+ # @api public
116
+ def self.to_decimal(input, &)
117
+ to_float(input) do
118
+ if block_given?
119
+ return yield
120
+ else
121
+ raise CoercionError, "#{input.inspect} cannot be coerced to decimal"
122
+ end
123
+ end
124
+
125
+ input.to_d
126
+ end
127
+
128
+ # @param [Array, String, Object] input
129
+ #
130
+ # @return [Array, Object]
131
+ #
132
+ # @raise CoercionError
133
+ #
134
+ # @api public
135
+ def self.to_ary(input, &)
136
+ if empty_str?(input)
137
+ []
138
+ elsif input.is_a?(::Array)
139
+ input
140
+ elsif block_given?
141
+ yield
142
+ else
143
+ raise CoercionError, "#{input.inspect} cannot be coerced to array"
144
+ end
145
+ end
146
+
147
+ # @param [Hash, String, Object] input
148
+ #
149
+ # @return [Hash, Object]
150
+ #
151
+ # @raise CoercionError
152
+ #
153
+ # @api public
154
+ def self.to_hash(input, &)
155
+ if empty_str?(input)
156
+ {}
157
+ elsif input.is_a?(::Hash)
158
+ input
159
+ elsif block_given?
160
+ yield
161
+ else
162
+ raise CoercionError, "#{input.inspect} cannot be coerced to hash"
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # Common coercion functions used by the built-in `Params` and `JSON` types
6
+ #
7
+ # @api public
8
+ module Coercions
9
+ include Dry::Core::Constants
10
+
11
+ # @param [#to_str, Object] input
12
+ #
13
+ # @return [Date, Object]
14
+ #
15
+ # @see Date.parse
16
+ #
17
+ # @api public
18
+ def to_date(input, &)
19
+ if input.respond_to?(:to_str)
20
+ begin
21
+ ::Date.parse(input)
22
+ rescue ::ArgumentError, ::RangeError => exception
23
+ CoercionError.handle(exception, &)
24
+ end
25
+ elsif input.is_a?(::Date)
26
+ input
27
+ elsif block_given?
28
+ yield
29
+ else
30
+ raise CoercionError, "#{input.inspect} is not a string"
31
+ end
32
+ end
33
+
34
+ # @param [#to_str, Object] input
35
+ #
36
+ # @return [DateTime, Object]
37
+ #
38
+ # @see DateTime.parse
39
+ #
40
+ # @api public
41
+ def to_date_time(input, &)
42
+ if input.respond_to?(:to_str)
43
+ begin
44
+ ::DateTime.parse(input)
45
+ rescue ::ArgumentError => exception
46
+ CoercionError.handle(exception, &)
47
+ end
48
+ elsif input.is_a?(::DateTime)
49
+ input
50
+ elsif block_given?
51
+ yield
52
+ else
53
+ raise CoercionError, "#{input.inspect} is not a string"
54
+ end
55
+ end
56
+
57
+ # @param [#to_str, Object] input
58
+ #
59
+ # @return [Time, Object]
60
+ #
61
+ # @see Time.parse
62
+ #
63
+ # @api public
64
+ def to_time(input, &)
65
+ if input.respond_to?(:to_str)
66
+ begin
67
+ ::Time.parse(input)
68
+ rescue ::ArgumentError => exception
69
+ CoercionError.handle(exception, &)
70
+ end
71
+ elsif input.is_a?(::Time)
72
+ input
73
+ elsif block_given?
74
+ yield
75
+ else
76
+ raise CoercionError, "#{input.inspect} is not a string"
77
+ end
78
+ end
79
+
80
+ # @param [#to_sym, Object] input
81
+ #
82
+ # @return [Symbol, Object]
83
+ #
84
+ # @raise CoercionError
85
+ #
86
+ # @api public
87
+ def to_symbol(input, &)
88
+ input.to_sym
89
+ rescue ::NoMethodError => exception
90
+ CoercionError.handle(exception, &)
91
+ end
92
+
93
+ private
94
+
95
+ # Checks whether String is empty
96
+ #
97
+ # @param [String, Object] value
98
+ #
99
+ # @return [Boolean]
100
+ #
101
+ # @api private
102
+ def empty_str?(value) = EMPTY_STRING.eql?(value)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1 @@
1
+ # frozen_string_literal: true
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # @api private
6
+ class Compiler
7
+ extend ::Dry::Core::Deprecations[:"dry-types"]
8
+
9
+ attr_reader :registry
10
+
11
+ def initialize(registry)
12
+ @registry = registry
13
+ end
14
+
15
+ def call(ast) = visit(ast)
16
+
17
+ def visit(node)
18
+ type, body = node
19
+ send(:"visit_#{type}", body)
20
+ end
21
+
22
+ def visit_constrained(node)
23
+ nominal, rule = node
24
+ type = visit(nominal)
25
+ type.constrained_type.new(type, rule: visit_rule(rule))
26
+ end
27
+
28
+ def visit_constructor(node)
29
+ nominal, fn = node
30
+ primitive = visit(nominal)
31
+ primitive.constructor(compile_fn(fn))
32
+ end
33
+
34
+ def visit_lax(node)
35
+ Types::Lax.new(visit(node))
36
+ end
37
+ deprecate(:visit_safe, :visit_lax)
38
+
39
+ def visit_nominal(node)
40
+ type, options, meta =
41
+ case node
42
+ in [type, options, meta]
43
+ node
44
+ in [type, meta]
45
+ [type, EMPTY_HASH, meta]
46
+ end
47
+
48
+ nominal_name = "nominal.#{Types.identifier(type)}"
49
+
50
+ if registry.registered?(nominal_name)
51
+ registry[nominal_name].with(**options).meta(meta)
52
+ else
53
+ Nominal.new(type, meta: meta, **options)
54
+ end
55
+ end
56
+
57
+ def visit_rule(node)
58
+ ::Dry::Types.rule_compiler.([node])[0]
59
+ end
60
+
61
+ def visit_sum(node)
62
+ *types, meta = node
63
+ types.map { |type| visit(type) }.reduce(:|).meta(meta)
64
+ end
65
+
66
+ def visit_array(node)
67
+ member, meta = node
68
+ member = visit(member) unless member.is_a?(::Class)
69
+ registry["nominal.array"].of(member).meta(meta)
70
+ end
71
+
72
+ def visit_hash(node)
73
+ opts, meta = node
74
+ registry["nominal.hash"].with(**opts, meta: meta)
75
+ end
76
+
77
+ def visit_schema(node)
78
+ keys, options, meta = node
79
+ registry["nominal.hash"].schema(keys.map { |key| visit(key) }).with(**options, meta: meta)
80
+ end
81
+
82
+ def visit_json_hash(node)
83
+ keys, meta = node
84
+ registry["json.hash"].schema(keys.map { |key| visit(key) }, meta)
85
+ end
86
+
87
+ def visit_json_array(node)
88
+ member, meta = node
89
+ registry["json.array"].of(visit(member)).meta(meta)
90
+ end
91
+
92
+ def visit_params_hash(node)
93
+ keys, meta = node
94
+ registry["params.hash"].schema(keys.map { |key| visit(key) }, meta)
95
+ end
96
+
97
+ def visit_params_array(node)
98
+ member, meta = node
99
+ registry["params.array"].of(visit(member)).meta(meta)
100
+ end
101
+
102
+ def visit_key(node)
103
+ name, required, type = node
104
+ Schema::Key.new(visit(type), name, required: required)
105
+ end
106
+
107
+ def visit_enum(node)
108
+ type, mapping = node
109
+ Enum.new(visit(type), mapping: mapping)
110
+ end
111
+
112
+ def visit_map(node)
113
+ key_type, value_type, meta = node
114
+ registry["nominal.hash"].map(visit(key_type), visit(value_type)).meta(meta)
115
+ end
116
+
117
+ def visit_any(meta)
118
+ registry["any"].meta(meta)
119
+ end
120
+
121
+ def compile_fn(fn)
122
+ type, *node = fn
123
+
124
+ case type
125
+ when :id
126
+ ::Dry::Types::FnContainer[node.fetch(0)]
127
+ when :callable
128
+ node.fetch(0)
129
+ when :method
130
+ target, method = node
131
+ target.method(method)
132
+ else
133
+ raise ::ArgumentError, "Cannot build callable from #{fn.inspect}"
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/core/equalizer"
4
+ require "dry/types/options"
5
+ require "dry/types/meta"
6
+
7
+ module Dry
8
+ module Types
9
+ module Composition
10
+ include Type
11
+ include Builder
12
+ include Options
13
+ include Meta
14
+ include Printable
15
+ include ::Dry::Equalizer(
16
+ :left, :right, :options, :meta,
17
+ inspect: false,
18
+ immutable: true
19
+ )
20
+
21
+ # @return [Type]
22
+ attr_reader :left
23
+
24
+ # @return [Type]
25
+ attr_reader :right
26
+
27
+ module Constrained
28
+ def rule
29
+ left.rule.public_send(self.class.operator, right.rule)
30
+ end
31
+
32
+ def constrained?
33
+ true
34
+ end
35
+ end
36
+
37
+ def self.included(base)
38
+ composition_name = Inflector.demodulize(base)
39
+ ast_type = Inflector.underscore(composition_name).to_sym
40
+ base.define_singleton_method(:ast_type) { ast_type }
41
+ base.define_singleton_method(:composition_name) { composition_name }
42
+ base.const_set("Constrained", ::Class.new(base) { include Constrained })
43
+ end
44
+
45
+ # @param [Type] left
46
+ # @param [Type] right
47
+ # @param [Hash] options
48
+ #
49
+ # @api private
50
+ def initialize(left, right, **options)
51
+ super
52
+ @left, @right = left, right
53
+ freeze
54
+ end
55
+
56
+ # @return [String]
57
+ #
58
+ # @api public
59
+ def name = "#{left.name} #{self.class.operator} #{right.name}"
60
+
61
+ # @return [false]
62
+ #
63
+ # @api public
64
+ def default? = false
65
+
66
+ # @return [false]
67
+ #
68
+ # @api public
69
+ def constrained? = false
70
+
71
+ # @return [Boolean]
72
+ #
73
+ # @api public
74
+ def optional? = false
75
+
76
+ # @param [Object] input
77
+ #
78
+ # @return [Object]
79
+ #
80
+ # @api private
81
+ def call_unsafe(input) = raise ::NotImplementedError
82
+
83
+ # @param [Object] input
84
+ #
85
+ # @return [Object]
86
+ #
87
+ # @api private
88
+ def call_safe(input, &) = raise ::NotImplementedError
89
+
90
+ # @param [Object] input
91
+ #
92
+ # @api public
93
+ def try(input, &) = raise ::NotImplementedError
94
+
95
+ # @api private
96
+ def success(input)
97
+ result = try(input)
98
+ if result.success?
99
+ result
100
+ else
101
+ raise ::ArgumentError, "Invalid success value '#{input}' for #{inspect}"
102
+ end
103
+ end
104
+
105
+ # @api private
106
+ def failure(input, _error = nil)
107
+ result = try(input)
108
+ if result.failure?
109
+ result
110
+ else
111
+ raise ::ArgumentError, "Invalid failure value '#{input}' for #{inspect}"
112
+ end
113
+ end
114
+
115
+ # @param [Object] value
116
+ #
117
+ # @return [Boolean]
118
+ #
119
+ # @api private
120
+ def primitive?(value) = raise ::NotImplementedError
121
+
122
+ # @see Nominal#to_ast
123
+ #
124
+ # @api public
125
+ def to_ast(meta: true)
126
+ [self.class.ast_type,
127
+ [left.to_ast(meta: meta), right.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
128
+ end
129
+
130
+ # Wrap the type with a proc
131
+ #
132
+ # @return [Proc]
133
+ #
134
+ # @api public
135
+ def to_proc = proc { |value| self.(value) }
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ class Constrained
6
+ # Common coercion-related API for constrained types
7
+ #
8
+ # @api public
9
+ class Coercible < Constrained
10
+ # @return [Object]
11
+ #
12
+ # @api private
13
+ def call_unsafe(input)
14
+ coerced = type.call_unsafe(input)
15
+ result = rule.(coerced)
16
+
17
+ if result.success?
18
+ coerced
19
+ else
20
+ raise ConstraintError.new(result, input)
21
+ end
22
+ end
23
+
24
+ # @return [Object]
25
+ #
26
+ # @api private
27
+ def call_safe(input)
28
+ coerced = type.call_safe(input) { return yield }
29
+
30
+ if rule[coerced]
31
+ coerced
32
+ else
33
+ yield(coerced)
34
+ end
35
+ end
36
+
37
+ # @see Dry::Types::Constrained#try
38
+ #
39
+ # @api public
40
+ def try(input, &)
41
+ result = type.try(input)
42
+
43
+ if result.success?
44
+ validation = rule.(result.input)
45
+
46
+ if validation.success?
47
+ result
48
+ else
49
+ failure = failure(result.input, ConstraintError.new(validation, input))
50
+ block_given? ? yield(failure) : failure
51
+ end
52
+ else
53
+ block_given? ? yield(result) : result
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end