power_converter 0.0.1 → 0.0.2

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
  SHA1:
3
- metadata.gz: 1ffe8e4ed7f1e0bdafe8e06f34abca7936df05eb
4
- data.tar.gz: 7be13e121f7797f707da2627fa048a7117d2888c
3
+ metadata.gz: 1bd5e2306a30c044d98fadc15a1a330cd485f34f
4
+ data.tar.gz: ebc9c3bed3649bd24f11fa6564e52a088a766d5a
5
5
  SHA512:
6
- metadata.gz: 6b61649071f7d32ed30c86ce4f4dc09a1a442f0d49c6ac8d255a7ab03b1e0c2b1326557e559a5e90a5d4b79fadca90c0e3f9628cd10ed05f6e46095cea677b2f
7
- data.tar.gz: a25a41c2d57a8241a307905ba9d9e6264d0133888bc56b181b52bddbc3beb0583b4816c7093234499bcd827b21be73c435a583e3c8353786832f76ca312aea33
6
+ metadata.gz: 53124e4dc414751702a99c3b8be7d61dc31cc275141ddc9a5a9fe0fa192a9890580c022e8190675932ea1406dbc362fa8b0877b8201f4b6f34f74aedb4b22a84
7
+ data.tar.gz: 93dae5155d1d25aaecac0c218d75a7fa9b734a3e7cf61663d4a427bf0e546d4a9d6a2e1b72c18dfa312debb6853a87a8c034c21582bf3503faf8628e57d19f0b
data/README.md CHANGED
@@ -1,13 +1,46 @@
1
1
  # PowerConverter
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/power_converter.svg)](http://badge.fury.io/rb/power_converter)
3
4
  [![Build Status](https://travis-ci.org/jeremyf/power_converter.png?branch=master)](https://travis-ci.org/jeremyf/power_converter)
4
5
  [![Documentation Status](http://inch-ci.org/github/jeremyf/power_converter.svg?branch=master)](http://inch-ci.org/github/jeremyf/power_converter)
5
6
  [![APACHE 2 License](http://img.shields.io/badge/APACHE2-license-blue.svg)](./LICENSE)
6
7
 
7
- A placeholder for implementing a conversion module pattern.
8
+ ## About
8
9
 
9
- Exposing a means of registering conversions. These can be accessed at the module
10
- level:
10
+ **PowerConverter** exposes a means for defining a named conversion method.
11
+
12
+ *What is a conversion method?*
13
+
14
+ > A well-established Ruby idiom for methods which "do the right thing" to
15
+ > convery any reasonable input value into a desired class.
16
+ >
17
+ > http://devblog.avdi.org/2012/05/07/a-ruby-conversion-idiom/
18
+
19
+ *Why conversion methods?*
20
+
21
+ Because software is all about addressing a mapping problem. In my experience
22
+ using conversion methods has provided a means for easing the movement across
23
+ application design boundaries.
24
+
25
+ *Why use the PowerConverter gem?*
26
+
27
+ Excellent question.
28
+
29
+ **The short-answer is consistency**. **PowerConverter** helps you compose
30
+ conversions that have a common form.
31
+
32
+ **The longer-answer** is again related to consistency. By using a common
33
+ mechanism for definition, I'm hoping to reduce the nuanced variations that come
34
+ from crafting conversions. They all have a very similar shape, and I'd like to
35
+ provide tooling to help keep that shape.
36
+
37
+ I would much rather focus on other concepts than "is this conversion method
38
+ similar enough to its sibling conversion methods?"
39
+
40
+ In other words, relying on a common interface for defining a conversion method
41
+ reduces the number surprises when interacting with conversion methods.
42
+
43
+ ## Usage
11
44
 
12
45
  ```ruby
13
46
  PowerConverter.define_conversion_for :boolean do |input|
@@ -19,4 +52,8 @@ PowerConverter.define_conversion_for :boolean do |input|
19
52
  end
20
53
 
21
54
  PowerConverter.convert(object, to: :boolean)
55
+
56
+ # OR
57
+
58
+ PowerConverter.convert_to_boolean(object)
22
59
  ```
@@ -1,5 +1,5 @@
1
1
  # :nodoc:
2
2
  module PowerConverter
3
3
  # :nodoc:
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.2"
5
5
  end
@@ -22,10 +22,27 @@ module PowerConverter
22
22
  # @param named_converter [#to_s]
23
23
  # @param defined_converter_names [Array]
24
24
  #
25
+ # You had one job...to register a converter. Now you get an exception.
26
+ #
25
27
  # @example
26
28
  # raise ConverterNotFoundError.new(:boolean, [:hello, :world])
27
29
  def initialize(named_converter, defined_converter_names)
28
- super("Unable to find PowerConverter for #{named_converter} in #{defined_converter_names.inspect}")
30
+ super("Unable to find PowerConverter for #{named_converter} in #{defined_converter_names.inspect}.")
31
+ end
32
+ end
33
+
34
+ # When you tried to convert something and it just won't convert, this is a
35
+ # great exception to raise.
36
+ class ConversionError < RuntimeError
37
+ # @param value [Object]
38
+ # @param named_converter [#to_s]
39
+ #
40
+ # Do or do not. There is no try.
41
+ #
42
+ # @example
43
+ # raise ConversionError.new(:boolean, [:hello, :world])
44
+ def initialize(value, named_converter)
45
+ super("Unable to convert #{value.inspect} to '#{named_converter}'.")
29
46
  end
30
47
  end
31
48
 
@@ -37,6 +54,10 @@ module PowerConverter
37
54
  # Responsible for defining a conversion method and a "shovel-ready" conversion
38
55
  # module; because maybe you want a mixin for convenience reasons.
39
56
  #
57
+ # @note If your defined converter returns `nil`, it is assumed if the
58
+ # conversion failed and a [PowerConverter::ConversionError] exception should
59
+ # be thrown.
60
+ #
40
61
  # @param named_conversion [String,Symbol] the name of the conversion that you
41
62
  # are declaring.
42
63
  # @param converter [#call] the callable object that will perform the
@@ -55,6 +76,10 @@ module PowerConverter
55
76
  # true
56
77
  # end
57
78
  # end
79
+ #
80
+ # PowerConverter.convert(object, to: :boolean)
81
+ # PowerConverter.convert_to_boolean(object)
82
+ #
58
83
  # @see http://devblog.avdi.org/2012/05/07/a-ruby-conversion-idiom/ Avdi
59
84
  # Grimm's post on "A Ruby Conversion Idiom"
60
85
  #
@@ -72,27 +97,45 @@ module PowerConverter
72
97
  # @api public
73
98
  # @since 0.0.1
74
99
  #
75
- # Convert the given `value` via the named `:to` converter.
100
+ # Convert the given `value` via the named `:to` converter. As a short-circuit
101
+ # if the given `value` publicly responds to a `to_<named_converter>` it will
102
+ # use that.
76
103
  #
77
104
  # @param value [Object] the thing that you will be converting
78
105
  # @param [Hash] options the options used to perform the conversion
79
106
  # @option options [Symbol] :to the named_conversion that has been registered
80
107
  #
108
+ # @return [Object] the resulting converted object
109
+ #
81
110
  # @raise [ConverterNotFoundError] if the named converter is not found
111
+ # @raise [ConversionError] if the named converter returned a nil value
82
112
  #
83
113
  # @see PowerConverter.define_conversion_for
84
114
  #
85
115
  # @example
86
116
  # PowerConverter.convert('true', to: :boolean)
87
117
  #
88
- # @todo I want to:
89
- # * raise an exception if I'm unable to convert an object
90
- # * auto-handle :to_<named_conversion> so I don't need to worry about
91
- # registering that.
118
+ # @example
119
+ # class Foo
120
+ # def to_bar
121
+ # :hello_world
122
+ # end
123
+ # end
124
+ #
125
+ # PowerConverter.convert(Foo.new, to: :bar)
126
+ # => :hello_world
127
+ #
92
128
  def convert(value, options = {})
93
- converter_for(options.fetch(:to)).call(value)
129
+ named_converter = options.fetch(:to)
130
+ return value.public_send("to_#{named_converter}") if value.respond_to?("to_#{named_converter}", false)
131
+ returning_value = converter_for(named_converter).call(value)
132
+ return returning_value unless returning_value.nil?
133
+ fail ConversionError.new(value, named_converter)
94
134
  end
95
135
 
136
+ # :nodoc:
137
+ CONVERSION_METHOD_PREFIX = "convert_to_".freeze
138
+
96
139
  # @api public
97
140
  # @since 0.0.1
98
141
  #
@@ -113,11 +156,16 @@ module PowerConverter
113
156
  # convert_to_boolean(@bar)
114
157
  # end
115
158
  # end
159
+ #
160
+ # @todo Allow for the inclusion of multiple power converter named types.
116
161
  def module_for(named_conversion)
117
- converter = converter_for(named_conversion)
118
162
  Module.new do
119
- define_method("convert_to_#{named_conversion}", &converter)
120
- private "convert_to_#{named_conversion}"
163
+ # HACK: I'd prefer to not lean on calling the underlying convert method
164
+ # which means I will likely need some converter builder behavior.
165
+ define_method("#{CONVERSION_METHOD_PREFIX}#{named_conversion}") do |value|
166
+ PowerConverter.convert(value, to: named_conversion)
167
+ end
168
+ private "#{CONVERSION_METHOD_PREFIX}#{named_conversion}"
121
169
  end
122
170
  end
123
171
 
@@ -152,4 +200,36 @@ module PowerConverter
152
200
  def defined_converter_names
153
201
  @defined_conversions.keys
154
202
  end
203
+
204
+ # :nodoc:
205
+ CONVERSION_METHOD_REGEXP = /\A#{CONVERSION_METHOD_PREFIX}(.*)\Z/.freeze
206
+
207
+ # :nodoc:
208
+ def method_missing(method_name, *args, &block)
209
+ named_converter = extract_named_converter_from(method_name)
210
+ if named_converter
211
+ convert(*args, to: named_converter)
212
+ else
213
+ super
214
+ end
215
+ end
216
+ private_class_method :method_missing
217
+
218
+ # :nodoc:
219
+ def extract_named_converter_from(method_name)
220
+ match = method_name.to_s.match(CONVERSION_METHOD_REGEXP)
221
+ match.captures[0] if match
222
+ end
223
+ private_class_method :extract_named_converter_from
224
+
225
+ # :nodoc:
226
+ def respond_to_missing?(method_name, include_private = false)
227
+ named_converter = extract_named_converter_from(method_name)
228
+ if named_converter
229
+ @defined_conversions.key?(named_converter.to_s)
230
+ else
231
+ super
232
+ end
233
+ end
234
+ private_class_method :respond_to_missing?
155
235
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: power_converter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Friesen