motion_coercible 0.2.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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ODBjMjc2YjRlNzQxNWQ5MDc2YTE0MDE4NGIzNTM5ZDZjMDlmMjg3OA==
5
+ data.tar.gz: !binary |-
6
+ ZDVjNmFjYjAyNjE1ODQzODQ4MDlkOTUzNzliODY0ZDJiNDIxMzBlZQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MzEyODc3ZjYzMGM0NTQ4MTVhNTlmZDNlYmViMWU4NTkyNjlkMjZkOTZhNmNi
10
+ OGEyNWRkYjU5Y2RiOWVkODJkYjRjOTM3NTc4MjMzMTAyYTVkZTVmZDI2Nzlj
11
+ OWUyNDRmNmMzNDZjZWZkNzBhZTM3YzgyN2JhYmY1NjNiYzU1YzM=
12
+ data.tar.gz: !binary |-
13
+ ZmZkMzM4MGIzYWMzYmYyMmU2ODY1MWNhODBkYWNhNDgyY2ZhMTJmNGY5NTEw
14
+ YWMwNzQzN2U2ODA5Y2JhNzIyYTEwNjBkZmVkYzY5MTQ3NTlmYTY1NzJjZTg2
15
+ ZmFmZTRjMTAxM2JmODg0OGJjYzczMzc2NzZjZWE5Mzk0NTE0MTA=
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # motion_coercible
2
+
3
+ A RubyMotion port of [solnic's](https://github.com/solnic) [coercible](https://github.com/solnic/coercible) library.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'motion_coercible'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install motion_coercible
18
+
19
+ ## Usage
20
+
21
+ Coercible gives you access to coercer objects where each object is responsible
22
+ for coercing only one type into other types. For example a string coercer knows
23
+ only how to coerce string objects, integer coercer knows only how to coerce integers
24
+ etc.
25
+
26
+ Here's the most basic example:
27
+
28
+ ```ruby
29
+ coercer = Coercible::Coercer.new
30
+
31
+ # coerce a string to a date
32
+ coercer[String].to_date('2012/12/25') # => #<Date: 4912573/2,0,2299161>
33
+
34
+ # coerce a string to a boolean value
35
+ coercer[String].to_boolean('yes') # => true
36
+
37
+ # you got the idea :)
38
+ ```
39
+
40
+ For more control you can configure your coercer like that:
41
+
42
+ ``` ruby
43
+ # build coercer instance
44
+ coercer = Coercible::Coercer.new do |config|
45
+ config.string.boolean_map = { 'yup' => true, 'nope' => false }
46
+ end
47
+
48
+ # coerce a string to boolean
49
+ coercer[String].to_boolean('yup') # => true
50
+ coercer[String].to_boolean('nope') # => false
51
+ ```
52
+
53
+ Note that at the moment only Integer and String are configurable. More configurable
54
+ coercers will be added later whenever we find good usecases.
55
+
56
+ ## Contributing
57
+
58
+ 1. Fork it
59
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
60
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
61
+ 4. Push to the branch (`git push origin my-new-feature`)
62
+ 5. Create new Pull Request
@@ -0,0 +1,12 @@
1
+ unless defined?(Motion::Project::Config)
2
+ raise "This file must be required within a RubyMotion project Rakefile."
3
+ end
4
+
5
+ require 'motion_descendants_tracker'
6
+
7
+ require 'motion-require'
8
+ Motion::Require.all(Dir.glob(File.expand_path('../project/**/*.rb', __FILE__)))
9
+
10
+ Motion::Project::App.setup do |app|
11
+ # configuration
12
+ end
@@ -0,0 +1,24 @@
1
+ module Coercible
2
+ class Coercer
3
+
4
+ # Coerce Array values
5
+ class Array < Object
6
+ primitive ::Array
7
+
8
+ TIME_SEGMENTS = [ :year, :month, :day, :hour, :min, :sec ].freeze
9
+
10
+ # Creates a Set instance from an Array
11
+ #
12
+ # @param [Array] value
13
+ #
14
+ # @return [Array]
15
+ #
16
+ # @api private
17
+ def to_set(value)
18
+ value.to_set
19
+ end
20
+
21
+ end # class Array
22
+
23
+ end # class Coercer
24
+ end # module Coercible
@@ -0,0 +1,63 @@
1
+ module Coercible
2
+ class Coercer
3
+
4
+ module Configurable
5
+
6
+ # Add configuration-specific option keys to the descendant
7
+ #
8
+ # @return [self]
9
+ #
10
+ # @api private
11
+ def self.extended(coercer)
12
+ coercer.accept_options :config_keys
13
+ super
14
+ end
15
+
16
+ # Build configuration object for the coercer class
17
+ #
18
+ # @example
19
+ #
20
+ # coercer_class = Class.new(Coercer::Object) do
21
+ # extend Configurable
22
+ #
23
+ # config_keys [ :foo, :bar ]
24
+ # end
25
+ #
26
+ # coercer_class.config do |config|
27
+ # config.foo = '1'
28
+ # config.bar = '2'
29
+ # end
30
+ #
31
+ # @yieldparam [Configuration]
32
+ #
33
+ # @return [Configuration]
34
+ #
35
+ # @api public
36
+ def config(&block)
37
+ configuration = configuration_class.build(config_keys)
38
+ yield configuration
39
+ configuration
40
+ end
41
+
42
+ # Return configuration name in the global config
43
+ #
44
+ # @return [Symbol]
45
+ #
46
+ # @api private
47
+ def config_name
48
+ name.downcase.split('::').last.to_sym
49
+ end
50
+
51
+ # Return configuration class
52
+ #
53
+ # @return [Class:Configuration]
54
+ #
55
+ # @api private
56
+ def configuration_class
57
+ Configuration
58
+ end
59
+
60
+ end # module Configurable
61
+
62
+ end # class Coercer
63
+ end # module Coercible
@@ -0,0 +1,25 @@
1
+ module Coercible
2
+ class Coercer
3
+
4
+ # Coerce false values
5
+ class FalseClass < Object
6
+ primitive ::FalseClass
7
+
8
+ # Coerce given value to String
9
+ #
10
+ # @example
11
+ # coercer[FalseClass].to_string(false) # => "false"
12
+ #
13
+ # @param [FalseClass] value
14
+ #
15
+ # @return [String]
16
+ #
17
+ # @api public
18
+ def to_string(value)
19
+ value.to_s
20
+ end
21
+
22
+ end # class FalseClass
23
+
24
+ end # class Coercer
25
+ end # module Coercible
@@ -0,0 +1,25 @@
1
+ module Coercible
2
+ class Coercer
3
+
4
+ # Coerce Float values
5
+ class Float < Numeric
6
+ primitive ::Float
7
+
8
+ # Passthrough the value
9
+ #
10
+ # @example
11
+ # coercer[Float].to_float(1.0) # => 1.0
12
+ #
13
+ # @param [Float] value
14
+ #
15
+ # @return [Integer]
16
+ #
17
+ # @api public
18
+ def to_float(value)
19
+ value
20
+ end
21
+
22
+ end # class Float
23
+
24
+ end # class Coercer
25
+ end # module Coercible
@@ -0,0 +1,46 @@
1
+ module Coercible
2
+ class Coercer
3
+
4
+ # Coerce Hash values
5
+ class Hash < Object
6
+ primitive ::Hash
7
+
8
+ TIME_SEGMENTS = [ :year, :month, :day, :hour, :min, :sec ].freeze
9
+
10
+ # Creates a Time instance from a Hash
11
+ #
12
+ # Valid keys are: :year, :month, :day, :hour, :min, :sec
13
+ #
14
+ # @param [Hash] value
15
+ #
16
+ # @return [Time]
17
+ #
18
+ # @api private
19
+ def to_time(value)
20
+ ::Time.local(*extract(value))
21
+ end
22
+
23
+ private
24
+
25
+ # Extracts the given args from a Hash
26
+ #
27
+ # If a value does not exist, it uses the value of Time.now
28
+ #
29
+ # @param [Hash] value
30
+ #
31
+ # @return [Array]
32
+ #
33
+ # @api private
34
+ def extract(value)
35
+ now = ::Time.now
36
+
37
+ TIME_SEGMENTS.map do |segment|
38
+ val = value.fetch(segment, now.public_send(segment))
39
+ coercers[val.class].to_integer(val)
40
+ end
41
+ end
42
+
43
+ end # class Hash
44
+
45
+ end # class Coercer
46
+ end # module Coercible
@@ -0,0 +1,92 @@
1
+ module Coercible
2
+ class Coercer
3
+
4
+ # Coerce Fixnum values
5
+ class Integer < Numeric
6
+ extend Configurable
7
+
8
+ primitive ::Integer
9
+
10
+ config_keys [ :boolean_map ]
11
+
12
+ # Return default config for Integer coercer type
13
+ #
14
+ # @return [Configuration]
15
+ #
16
+ # @see Configurable#config
17
+ #
18
+ # @api private
19
+ def self.config
20
+ super do |config|
21
+ config.boolean_map = { 0 => false, 1 => true }
22
+ end
23
+ end
24
+
25
+ # Return boolean map from config
26
+ #
27
+ # @return [::Hash]
28
+ #
29
+ # @api private
30
+ attr_reader :boolean_map
31
+
32
+ # Initialize a new Integer coercer instance and set its configuration
33
+ #
34
+ # @return [undefined]
35
+ #
36
+ # @api private
37
+ def initialize(coercer = Coercer.new, config = self.class.config)
38
+ super(coercer)
39
+ @boolean_map = config.boolean_map
40
+ end
41
+
42
+ # Coerce given value to String
43
+ #
44
+ # @example
45
+ # coercer[Integer].to_string(1) # => "1"
46
+ #
47
+ # @param [Fixnum] value
48
+ #
49
+ # @return [String]
50
+ #
51
+ # @api public
52
+ def to_string(value)
53
+ value.to_s
54
+ end
55
+
56
+ # Passthrough the value
57
+ #
58
+ # @example
59
+ # coercer[Integer].to_integer(1) # => 1
60
+ #
61
+ # @param [Fixnum] value
62
+ #
63
+ # @return [Float]
64
+ #
65
+ # @api public
66
+ def to_integer(value)
67
+ value
68
+ end
69
+
70
+ # Coerce given value to a Boolean
71
+ #
72
+ # @example with a 1
73
+ # coercer[Integer].to_boolean(1) # => true
74
+ #
75
+ # @example with a 0
76
+ # coercer[Integer].to_boolean(0) # => false
77
+ #
78
+ # @param [Fixnum] value
79
+ #
80
+ # @return [BigDecimal]
81
+ #
82
+ # @api public
83
+ def to_boolean(value)
84
+ boolean_map.fetch(value) {
85
+ raise_unsupported_coercion(value, __method__)
86
+ }
87
+ end
88
+
89
+ end # class Fixnum
90
+
91
+ end # class Coercer
92
+ end # module Coercible
@@ -0,0 +1,53 @@
1
+ module Coercible
2
+ class Coercer
3
+
4
+ # Base class for all numeric Coercion classes
5
+ class Numeric < Object
6
+ primitive ::Numeric
7
+
8
+ # Coerce given value to String
9
+ #
10
+ # @example
11
+ # coercer[Numeric].to_string(Rational(2, 2)) # => "1.0"
12
+ #
13
+ # @param [Numeric] value
14
+ #
15
+ # @return [String]
16
+ #
17
+ # @api public
18
+ def to_string(value)
19
+ value.to_s
20
+ end
21
+
22
+ # Creates an Integer instance from a numeric object
23
+ #
24
+ # @example
25
+ # coercer[Numeric].to_integer(Rational(2, 2)) # => 1
26
+ #
27
+ # @param [Numeric] value
28
+ #
29
+ # @return [Integer]
30
+ #
31
+ # @api public
32
+ def to_integer(value)
33
+ value.to_i
34
+ end
35
+
36
+ # Creates a Float instance from a numeric object
37
+ #
38
+ # @example
39
+ # coercer[Numeric].to_float(Rational(2, 2)) # => 1.0
40
+ #
41
+ # @param [Numeric] value
42
+ #
43
+ # @return [Float]
44
+ #
45
+ # @api public
46
+ def to_float(value)
47
+ value.to_f
48
+ end
49
+
50
+ end # class Numeric
51
+
52
+ end # class Coercer
53
+ end # module Coercible
@@ -0,0 +1,187 @@
1
+ module Coercible
2
+ class Coercer
3
+
4
+ # Coerce Object values
5
+ class Object
6
+ extend TypeLookup, Options
7
+
8
+ accept_options :primitive
9
+
10
+ primitive ::Object
11
+
12
+ COERCION_METHOD_REGEXP = /\Ato_/.freeze
13
+
14
+ # Return coercers object
15
+ #
16
+ # @return [Coercer]
17
+ #
18
+ # @api private
19
+ attr_reader :coercers
20
+
21
+ # Initialize a new coercer instance
22
+ #
23
+ # @param [Coercer] coercers
24
+ #
25
+ # @return [undefined]
26
+ #
27
+ # @api private
28
+ def initialize(coercers = Coercer.new)
29
+ @coercers = coercers
30
+ end
31
+
32
+ # Inspect the coercer object
33
+ #
34
+ # @example
35
+ # coercer[Object].inspect # => "<Coercer::Object primitive=Object>"
36
+ #
37
+ # @return [String]
38
+ #
39
+ # @api public
40
+ def inspect
41
+ "#<#{self.class} primitive=#{self.class.primitive}>"
42
+ end
43
+
44
+ # Create an Array from any Object
45
+ #
46
+ # @example with an object that does not respond to #to_a or #to_ary
47
+ # coercer[Object].to_array(value) # => [ value ]
48
+ #
49
+ # @example with an object that responds to #to_a
50
+ # coercer[Object].to_array(Set[ value ]) # => [ value ]
51
+ #
52
+ # @example with n object that responds to #to_ary
53
+ # coercer[Object].to_array([ value ]) # => [ value ]
54
+ #
55
+ # @param [#to_a,#to_ary,Object] value
56
+ # @param [#to_a,#to_ary,Object] value
57
+ #
58
+ # @return [Array]
59
+ #
60
+ # @api public
61
+ def to_array(value)
62
+ Array(value)
63
+ end
64
+
65
+ # Create a Hash from the Object if possible
66
+ #
67
+ # @example with a coercible object
68
+ # coercer[Object].to_hash(key => value) # => { key => value }
69
+ #
70
+ # @example with an object that is not coercible
71
+ # coercer[Object].to_hash(value) # => value
72
+ #
73
+ # @param [#to_hash, Object] value
74
+ #
75
+ # @return [Hash]
76
+ # returns a Hash when the object can be coerced
77
+ # @return [Object]
78
+ # returns the value when the object cannot be coerced
79
+ #
80
+ # @api public
81
+ def to_hash(value)
82
+ coerce_with_method(value, :to_hash, __method__)
83
+ end
84
+
85
+ # Create a String from the Object if possible
86
+ #
87
+ # @example with a coercible object
88
+ # coercer[Object].to_string("string") # => "string"
89
+ #
90
+ # @example with an object that is not coercible
91
+ # coercer[Object].to_string(value) # => value
92
+ #
93
+ # @param [#to_str, Object] value
94
+ #
95
+ # @return [String]
96
+ # returns a String when the object can be coerced
97
+ # @return [Object]
98
+ # returns the value when the object cannot be coerced
99
+ #
100
+ # @api public
101
+ def to_string(value)
102
+ coerce_with_method(value, :to_str, __method__)
103
+ end
104
+
105
+ # Create an Integer from the Object if possible
106
+ #
107
+ # @example with a coercible object
108
+ # coercer[Object].to_integer(1) # => 1
109
+ #
110
+ # @example with an object that is not coercible
111
+ # coercer[Object].to_integer(value) # => value
112
+ #
113
+ # @param [#to_int, Object] value
114
+ #
115
+ # @return [Integer]
116
+ # returns an Integer when the object can be coerced
117
+ # @return [Object]
118
+ # returns the value when the object cannot be coerced
119
+ #
120
+ # @api public
121
+ def to_integer(value)
122
+ coerce_with_method(value, :to_int, __method__)
123
+ end
124
+
125
+ # Return if the value was successfuly coerced
126
+ #
127
+ # @example when coercion was successful
128
+ # coercer[String].coerced?(1) # => true
129
+ #
130
+ # @example when coercion was NOT successful
131
+ # coercer[String].coerced?("foo") # => false
132
+ #
133
+ # @return [TrueClass,FalseClass]
134
+ #
135
+ # @api public
136
+ def coerced?(value)
137
+ value.kind_of?(self.class.primitive)
138
+ end
139
+
140
+ private
141
+
142
+ # Raise an unsupported coercion error
143
+ #
144
+ # @raises [UnsupportedCoercion]
145
+ #
146
+ # @return [undefined]
147
+ #
148
+ # @api private
149
+ def raise_unsupported_coercion(value, method)
150
+ raise(
151
+ UnsupportedCoercion,
152
+ "#{self.class}##{method} doesn't know how to coerce #{value.inspect}"
153
+ )
154
+ end
155
+
156
+ # Passthrough given value
157
+ #
158
+ # @param [Object] value
159
+ #
160
+ # @return [Object]
161
+ #
162
+ # @api private
163
+ def method_missing(method, *args)
164
+ if method.to_s =~ COERCION_METHOD_REGEXP && args.size == 1
165
+ args.first
166
+ else
167
+ super
168
+ end
169
+ end
170
+
171
+ # Try to use native coercion method on the given value
172
+ #
173
+ # @param [Object] value
174
+ #
175
+ # @param [Symbol] method
176
+ #
177
+ # @return [Object]
178
+ #
179
+ # @api private
180
+ def coerce_with_method(value, method, ref_method)
181
+ value.respond_to?(method) ? value.public_send(method) : raise_unsupported_coercion(value, ref_method)
182
+ end
183
+
184
+ end # class Object
185
+
186
+ end # class Coercer
187
+ end # module Coercible