motion_coercible 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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