transproc 0.2.3 → 0.2.4

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: a5ce7c814504a4dbdb337c06e34e0d8ba76240c2
4
- data.tar.gz: 7634b2a430e84411fdf9b3454f8a9e530167efef
3
+ metadata.gz: 18747dd5f157b683c7f3fc9200c7a7eb084cb270
4
+ data.tar.gz: 6961af7f27c18df6f9da0e3b0cbf839a003c839f
5
5
  SHA512:
6
- metadata.gz: 03cdc29204c0aeec12217dfc88a838d052fa3dbed8be7b66c1c8326ccd09bb9a0a2445dd4c535916da0e0fa2546340882867adcc897586e1e0f2b42244cf1c74
7
- data.tar.gz: a0c2124b3455b1d240a27420214a0ba5b31c8114a2002032fba26e02938fdb1ed99183a2b4a01bfdc250e16fd58a06b92612a78f5b7c8e017e95ab20bf6efabe
6
+ metadata.gz: 51f5533988a1658e74988a7176936aac2d97925624720ac74dc5ca3ffc51651f61732947e645a3b65ed430992d442ae5aff4d8d35a81acc2bcaae45a7bdb9d77
7
+ data.tar.gz: 0b665c3972a08d45fed440025c3c986dfb00726615c16ed4e52c29ac9a86ca7e6e91d9cd8275f32829b638b21edea9a4ba8813b8e673f0839e9576d54d4cefa0
@@ -1,3 +1,17 @@
1
+ ## v0.2.4 2015-06-20
2
+
3
+ ### Added
4
+
5
+ * `Transproc::Registry` extension for registering reusable functions within modules (nepalez)
6
+ * `:recursion` recurse over an enumerable (AMHOL)
7
+
8
+ ### Changed
9
+
10
+ * `:group`, `:nest`, and `:wrap` support adding new data to existing groups/wraps (nepalez)
11
+ * `Transproc::MalformedInputError` includes original backtrace now (solnic)
12
+
13
+ [Compare v0.2.3...v0.2.4](https://github.com/solnic/transproc/compare/v0.2.3...v0.2.4)
14
+
1
15
  ## v0.2.3 2015-06-02
2
16
 
3
17
  ### Added
data/Gemfile CHANGED
@@ -5,9 +5,12 @@ gemspec
5
5
  group :test do
6
6
  gem 'equalizer'
7
7
  gem 'anima'
8
- gem 'mutant'
9
- gem 'mutant-rspec'
10
8
  gem 'codeclimate-test-reporter', require: nil
9
+
10
+ platform :mri do
11
+ gem 'mutant', github: 'mbj/mutant', branch: 'master'
12
+ gem 'mutant-rspec'
13
+ end
11
14
  end
12
15
 
13
16
  group :tools do
@@ -3,6 +3,7 @@ require 'transproc/function'
3
3
  require 'transproc/functions'
4
4
  require 'transproc/composer'
5
5
  require 'transproc/error'
6
+ require 'transproc/registry'
6
7
 
7
8
  module Transproc
8
9
  module_function
@@ -21,7 +22,7 @@ module Transproc
21
22
  def register(*args, &block)
22
23
  name, fn = *args
23
24
  if functions.include?(name)
24
- raise FunctionAlreadyRegisteredError, "function #{name} is already defined"
25
+ raise FunctionAlreadyRegisteredError, "Function #{name} is already defined"
25
26
  end
26
27
  functions[name] = fn || block
27
28
  end
@@ -33,7 +34,7 @@ module Transproc
33
34
  # @api private
34
35
  def [](name)
35
36
  functions.fetch(name) {
36
- raise FunctionNotFoundError, "no registered function for #{name}"
37
+ raise FunctionNotFoundError, "No registered function for #{name}"
37
38
  }
38
39
  end
39
40
 
@@ -1,3 +1,5 @@
1
+ require 'transproc/coercions'
2
+
1
3
  module Transproc
2
4
  # Transformation functions for Array objects
3
5
  #
@@ -87,13 +89,15 @@ module Transproc
87
89
  def group(array, key, keys)
88
90
  grouped = Hash.new { |h, k| h[k] = [] }
89
91
  array.each do |hash|
90
- hash = hash.dup
91
- child = {}
92
- keys.each { |k| child[k] = hash.delete(k) }
93
- grouped[hash] << child
92
+ hash = Hash[hash]
93
+
94
+ old_group = Transproc::Coercions.to_tuples(hash.delete(key))
95
+ new_group = keys.inject({}) { |a, e| a.merge(e => hash.delete(e)) }
96
+
97
+ grouped[hash] << old_group.map { |item| item.merge(new_group) }
94
98
  end
95
99
  grouped.map do |root, children|
96
- root.merge(key => children)
100
+ root.merge(key => children.flatten)
97
101
  end
98
102
  end
99
103
 
@@ -153,5 +153,25 @@ module Transproc
153
153
  def to_datetime(value)
154
154
  DateTime.parse(value)
155
155
  end
156
+
157
+ # Coerce value into an array containing tuples only
158
+ #
159
+ # If the source is not an array, or doesn't contain a tuple, returns
160
+ # an array with one empty tuple
161
+ #
162
+ # @example
163
+ # Transproc(:to_tuples)[:foo] # => [{}]
164
+ # Transproc(:to_tuples)[[]] # => [{}]
165
+ # Transproc(:to_tuples)[[{ foo: :FOO, :bar }]] # => [{ foo: :FOO }]
166
+ #
167
+ # @param [Object] value
168
+ #
169
+ # @return [Array<Hash>]
170
+ #
171
+ def to_tuples(value)
172
+ array = value.is_a?(Array) ? Array[*value] : [{}]
173
+ array.select! { |item| item.is_a?(Hash) }
174
+ array.any? ? array : [{}]
175
+ end
156
176
  end
157
177
  end
@@ -4,13 +4,14 @@ module Transproc
4
4
  FunctionAlreadyRegisteredError = Class.new(Error)
5
5
 
6
6
  class MalformedInputError < Error
7
+ attr_reader :function, :value, :original_error
8
+
7
9
  def initialize(function, value, error)
8
10
  @function = function
9
11
  @value = value
10
12
  @original_error = error
11
- super("failed to call function #{function} on #{value}, #{error}")
13
+ super "Failed to call_function #{function} with #{value.inspect} - #{error}"
14
+ set_backtrace(error.backtrace)
12
15
  end
13
-
14
- attr_reader :function, :value, :original_error
15
16
  end
16
17
  end
@@ -23,9 +23,9 @@ module Transproc
23
23
  attr_reader :args
24
24
 
25
25
  # @api private
26
- def initialize(fn, options = {})
26
+ def initialize(fn, options)
27
27
  @fn = fn
28
- @args = options.fetch(:args) { [] }
28
+ @args = options[:args]
29
29
  end
30
30
 
31
31
  # Call the wrapped proc
@@ -37,8 +37,8 @@ module Transproc
37
37
  # @api public
38
38
  def call(*value)
39
39
  fn[*value, *args]
40
- rescue => ex
41
- raise MalformedInputError.new(@fn, value, ex)
40
+ rescue => e
41
+ raise MalformedInputError.new(@fn, value, e)
42
42
  end
43
43
  alias_method :[], :call
44
44
 
@@ -63,7 +63,7 @@ module Transproc
63
63
  #
64
64
  # @api public
65
65
  def to_ast
66
- identifier = fn.is_a?(::Proc) ? fn : fn.name
66
+ identifier = fn.instance_of?(Proc) ? fn : fn.name
67
67
  [identifier, args]
68
68
  end
69
69
  end
@@ -174,7 +174,7 @@ module Transproc
174
174
  #
175
175
  # @example
176
176
  # Transproc(:accept_keys, [:name])[name: 'Jane', email: 'jane@doe.org']
177
- # # => {:email => "jane@doe.org"}
177
+ # # => {:name=>"Jane"}
178
178
  #
179
179
  # @param [Hash] hash The input hash
180
180
  # @param [Array] keys The keys to be accepted
@@ -244,7 +244,9 @@ module Transproc
244
244
 
245
245
  if nest_keys.size > 0
246
246
  child = Hash[nest_keys.zip(nest_keys.map { |key| hash.delete(key) })]
247
- hash.update(root => child)
247
+ old_nest = hash[root]
248
+ new_nest = old_nest.is_a?(Hash) ? old_nest.merge(child) : child
249
+ hash.update(root => new_nest)
248
250
  else
249
251
  hash.update(root => {})
250
252
  end
@@ -302,7 +304,7 @@ module Transproc
302
304
  #
303
305
  # @api public
304
306
  def fold(hash, key, tuple_key)
305
- fold!(hash.dup, key, tuple_key)
307
+ fold!(Hash[hash], key, tuple_key)
306
308
  end
307
309
 
308
310
  # Same as `:fold` but mutates the hash
@@ -311,7 +313,7 @@ module Transproc
311
313
  #
312
314
  # @api public
313
315
  def fold!(hash, key, tuple_key)
314
- hash.merge!(key => ArrayTransformations.extract_key(hash[key], tuple_key))
316
+ hash.update(key => ArrayTransformations.extract_key(hash[key], tuple_key))
315
317
  end
316
318
 
317
319
  # Splits hash to array by all values from a specified key
@@ -328,7 +330,7 @@ module Transproc
328
330
  # { title: 'be cool' }
329
331
  # ]
330
332
  # }
331
- # Transproc(:split, :tasks, [:priority])
333
+ # Transproc(:split, :tasks, [:priority])[input]
332
334
  # => [
333
335
  # { name: 'Joe', priority: 1, tasks: [{ title: 'sleep well' }] },
334
336
  # { name: 'Joe', priority: 2, tasks: [{ title: 'be nice' }, { title: nil }] },
@@ -17,10 +17,50 @@ module Transproc
17
17
  module Recursion
18
18
  extend Functions
19
19
 
20
+ IF_ENUMERABLE = -> fn { Transproc(:is, Enumerable, fn) }
21
+
20
22
  IF_ARRAY = -> fn { Transproc(:is, Array, fn) }
21
23
 
22
24
  IF_HASH = -> fn { Transproc(:is, Hash, fn) }
23
25
 
26
+ # Recursively apply the provided transformation function to an enumerable
27
+ #
28
+ # @example
29
+ # Transproc(:recursion, Transproc(:is, ::Hash, Transproc(:symbolize_keys)))[
30
+ # {
31
+ # 'id' => 1,
32
+ # 'name' => 'Jane',
33
+ # 'tasks' => [
34
+ # { 'id' => 1, 'description' => 'Write some code' },
35
+ # { 'id' => 2, 'description' => 'Write some more code' }
36
+ # ]
37
+ # }
38
+ # ]
39
+ # => {:id=>1, :name=>"Jane", :tasks=>[{:id=>1, :description=>"Write some code"}, {:id=>2, :description=>"Write some more code"}]}
40
+ #
41
+ # @param [Enumerable]
42
+ #
43
+ # @return [Enumerable]
44
+ #
45
+ # @api public
46
+ def recursion(value, fn)
47
+ result = fn[value]
48
+ guarded = IF_ENUMERABLE[-> v { recursion(v, fn) }]
49
+
50
+ case result
51
+ when ::Hash
52
+ result.keys.each do |key|
53
+ result[key] = guarded[result.delete(key)]
54
+ end
55
+ when ::Array
56
+ result.map! do |item|
57
+ guarded[item]
58
+ end
59
+ end
60
+
61
+ result
62
+ end
63
+
24
64
  # Recursively apply the provided transformation function to an array
25
65
  #
26
66
  # @example
@@ -36,7 +76,7 @@ module Transproc
36
76
  # @api public
37
77
  def array_recursion(value, fn)
38
78
  result = fn[value]
39
- guarded = IF_ARRAY[-> v { Transproc(:array_recursion, fn)[v] }]
79
+ guarded = IF_ARRAY[-> v { array_recursion(v, fn) }]
40
80
 
41
81
  result.map! do |item|
42
82
  guarded[item]
@@ -58,7 +98,7 @@ module Transproc
58
98
  # @api public
59
99
  def hash_recursion(value, fn)
60
100
  result = fn[value]
61
- guarded = IF_HASH[-> v { Transproc(:hash_recursion, fn)[v] }]
101
+ guarded = IF_HASH[-> v { hash_recursion(v, fn) }]
62
102
 
63
103
  result.keys.each do |key|
64
104
  result[key] = guarded[result.delete(key)]
@@ -0,0 +1,126 @@
1
+ module Transproc
2
+ # Container to define transproc functions in, and access them via `[]` method
3
+ # from the outside of the module
4
+ #
5
+ # @example
6
+ # module FooMethods
7
+ # extend Transproc::Registry
8
+ #
9
+ # def foo(name, prefix)
10
+ # [prefix, '_', name].join
11
+ # end
12
+ # end
13
+ #
14
+ # fn = FooMethods[:foo, 'baz']
15
+ # fn['qux'] # => 'qux_baz'
16
+ #
17
+ # module BarMethods
18
+ # # extend Transproc::Registry
19
+ # include FooMethods
20
+ #
21
+ # def bar(*args)
22
+ # foo(*args).upcase
23
+ # end
24
+ # end
25
+ #
26
+ # fn = BarMethods[:foo, 'baz']
27
+ # fn['qux'] # => 'qux_baz'
28
+ #
29
+ # fn = BarMethods[:bar, 'baz']
30
+ # fn['qux'] # => 'QUX_BAZ'
31
+ #
32
+ # @api public
33
+ module Registry
34
+ # Builds the transproc function either from a Proc, or from the module method
35
+ #
36
+ # @param [Proc, Symbol] fn
37
+ # Either a proc, or a name of the module's function to be wrapped to transproc
38
+ # @param [Object, Array] args
39
+ # Args to be carried by the transproc
40
+ #
41
+ # @return [Transproc::Function]
42
+ #
43
+ # @alias :t
44
+ #
45
+ # @api public
46
+ def [](fn, *args)
47
+ fun = fn.is_a?(Proc) ? fn : method(fn).to_proc
48
+ Transproc::Function.new(fun, args: args)
49
+ end
50
+ alias_method :t, :[]
51
+
52
+ # Forwards the named method (transproc) to another module
53
+ #
54
+ # Allows using transprocs from other modules without including those
55
+ # modules as a whole
56
+ #
57
+ # @example
58
+ # module Foo
59
+ # extend Transproc::Registry
60
+ #
61
+ # def foo(value)
62
+ # value.upcase
63
+ # end
64
+ #
65
+ # def bar(value)
66
+ # value.downcase
67
+ # end
68
+ # end
69
+ #
70
+ # module Bar
71
+ # extend Transproc::Registry
72
+ #
73
+ # uses :foo, from: Foo, as: :baz
74
+ # uses :bar, from: Foo
75
+ # end
76
+ #
77
+ # Bar[:baz]['Qux'] # => 'QUX'
78
+ # Bar[:bar]['Qux'] # => 'qux'
79
+ #
80
+ # @param [String, Symbol] name
81
+ # @option [Class] :from The module to take the method from
82
+ # @option [String, Symbol] :as
83
+ # The name of imported transproc inside the current module
84
+ #
85
+ # @return [undefined]
86
+ #
87
+ # @api public
88
+ def uses(name, options = {})
89
+ source = options.fetch(:from)
90
+ new_name = options.fetch(:as, name)
91
+ define_method(new_name) { |*args| source.__send__(name, *args) }
92
+ end
93
+
94
+ # @api private
95
+ def self.extended(target)
96
+ target.extend(ClassMethods)
97
+ end
98
+
99
+ # @api private
100
+ module ClassMethods
101
+ # Makes `[]` and all functions defined in the included modules
102
+ # accessible in their receiver
103
+ #
104
+ # @api private
105
+ def included(other)
106
+ other.extend(Transproc::Registry, self)
107
+ end
108
+
109
+ # Makes newly module-defined functions accessible via `[]` method
110
+ # by adding it to the module's eigenclass
111
+ #
112
+ # @api private
113
+ def method_added(name)
114
+ module_function(name)
115
+ end
116
+
117
+ # Makes undefined methods inaccessible via `[]` method by
118
+ # undefining it from the module's eigenclass
119
+ #
120
+ # @api private
121
+ def method_undefined(name)
122
+ singleton_class.__send__(:undef_method, name)
123
+ end
124
+ end
125
+ end
126
+ end
@@ -1,3 +1,3 @@
1
1
  module Transproc
2
- VERSION = '0.2.3'.freeze
2
+ VERSION = '0.2.4'.freeze
3
3
  end
@@ -12,6 +12,9 @@ begin
12
12
  rescue LoadError
13
13
  end
14
14
 
15
+ root = Pathname(__FILE__).dirname
16
+ Dir[root.join('support/*.rb').to_s].each { |f| require f }
17
+
15
18
  RSpec.configure do |config|
16
19
  config.include(Transproc::Helper)
17
20
  end
@@ -0,0 +1,10 @@
1
+ module Mutant
2
+ class Selector
3
+ # Expression based test selector
4
+ class Expression < self
5
+ def call(_subject)
6
+ integration.all_tests
7
+ end
8
+ end # Expression
9
+ end # Selector
10
+ end # Mutant
@@ -175,17 +175,69 @@ describe Transproc::ArrayTransformations do
175
175
 
176
176
  expect(wrap[input]).to eql(output)
177
177
  end
178
+
179
+ it 'adds data to the existing tuples' do
180
+ wrap = t(:wrap, :task, [:title])
181
+
182
+ input = [{ name: 'Jane', task: { priority: 1 }, title: 'One' }]
183
+ output = [{ name: 'Jane', task: { priority: 1, title: 'One' } }]
184
+
185
+ expect(wrap[input]).to eql(output)
186
+ end
178
187
  end
179
188
 
180
189
  describe '.group' do
181
- it 'returns a new array with grouped hashes' do
182
- group = t(:group, :tasks, [:title])
190
+ subject(:group) { t(:group, :tasks, [:title]) }
183
191
 
184
- input = [{ name: 'Jane', title: 'One' }, { name: 'Jane', title: 'Two' }]
192
+ it 'returns a new array with grouped hashes' do
193
+ input = [{ name: 'Jane', title: 'One' }, { name: 'Jane', title: 'Two' }]
185
194
  output = [{ name: 'Jane', tasks: [{ title: 'One' }, { title: 'Two' }] }]
186
195
 
187
196
  expect(group[input]).to eql(output)
188
197
  end
198
+
199
+ it 'updates the existing group' do
200
+ input = [
201
+ {
202
+ name: 'Jane',
203
+ title: 'One',
204
+ tasks: [{ type: 'one' }, { type: 'two' }]
205
+ },
206
+ {
207
+ name: 'Jane',
208
+ title: 'Two',
209
+ tasks: [{ type: 'one' }, { type: 'two' }]
210
+ }
211
+ ]
212
+ output = [
213
+ {
214
+ name: 'Jane',
215
+ tasks: [
216
+ { title: 'One', type: 'one' },
217
+ { title: 'One', type: 'two' },
218
+ { title: 'Two', type: 'one' },
219
+ { title: 'Two', type: 'two' }
220
+ ]
221
+ }
222
+ ]
223
+
224
+ expect(group[input]).to eql(output)
225
+ end
226
+
227
+ it 'ingnores old values except for array of tuples' do
228
+ input = [
229
+ { name: 'Jane', title: 'One', tasks: [{ priority: 1 }, :wrong] },
230
+ { name: 'Jane', title: 'Two', tasks: :wrong }
231
+ ]
232
+ output = [
233
+ {
234
+ name: 'Jane',
235
+ tasks: [{ title: 'One', priority: 1 }, { title: 'Two' }]
236
+ }
237
+ ]
238
+
239
+ expect(group[input]).to eql(output)
240
+ end
189
241
  end
190
242
 
191
243
  describe '.ungroup' do
@@ -211,6 +263,34 @@ describe Transproc::ArrayTransformations do
211
263
 
212
264
  expect(ungroup[input]).to eql(output)
213
265
  end
266
+
267
+ it 'ungroups array partially' do
268
+ input = [
269
+ {
270
+ name: 'Jane',
271
+ tasks: [
272
+ { title: 'One', type: 'one' },
273
+ { title: 'One', type: 'two' },
274
+ { title: 'Two', type: 'one' },
275
+ { title: 'Two', type: 'two' }
276
+ ]
277
+ }
278
+ ]
279
+ output = [
280
+ {
281
+ name: 'Jane',
282
+ title: 'One',
283
+ tasks: [{ type: 'one' }, { type: 'two' }]
284
+ },
285
+ {
286
+ name: 'Jane',
287
+ title: 'Two',
288
+ tasks: [{ type: 'one' }, { type: 'two' }]
289
+ }
290
+ ]
291
+
292
+ expect(ungroup[input]).to eql(output)
293
+ end
214
294
  end
215
295
 
216
296
  describe '.combine' do
@@ -79,4 +79,38 @@ describe Transproc::Coercions do
79
79
  end
80
80
  end
81
81
  end
82
+
83
+ describe '.to_tuples' do
84
+ subject(:to_tuples) { t(:to_tuples) }
85
+
86
+ context 'non-array' do
87
+ let(:input) { :foo }
88
+
89
+ it 'returns an array with one blank tuple' do
90
+ output = [{}]
91
+
92
+ expect(to_tuples[input]).to eql(output)
93
+ end
94
+ end
95
+
96
+ context 'empty array' do
97
+ let(:input) { [] }
98
+
99
+ it 'returns an array with one blank tuple' do
100
+ output = [{}]
101
+
102
+ expect(to_tuples[input]).to eql(output)
103
+ end
104
+ end
105
+
106
+ context 'array of tuples' do
107
+ let(:input) { [:foo, { bar: :BAZ }, :qux] }
108
+
109
+ it 'returns an array with tuples only' do
110
+ output = [{ bar: :BAZ }]
111
+
112
+ expect(to_tuples[input]).to eql(output)
113
+ end
114
+ end
115
+ end
82
116
  end
@@ -172,6 +172,28 @@ describe Transproc::HashTransformations do
172
172
  expect(input).to eql(output)
173
173
  end
174
174
 
175
+ it 'returns new hash with keys nested under the existing key' do
176
+ nest = t(:nest!, :baz, ['two'])
177
+
178
+ input = { 'foo' => 'bar', baz: { 'one' => nil }, 'two' => false }
179
+ output = { 'foo' => 'bar', baz: { 'one' => nil, 'two' => false } }
180
+
181
+ nest[input]
182
+
183
+ expect(input).to eql(output)
184
+ end
185
+
186
+ it 'rewrites the existing key if its value is not a hash' do
187
+ nest = t(:nest!, :baz, ['two'])
188
+
189
+ input = { 'foo' => 'bar', baz: 'one', 'two' => false }
190
+ output = { 'foo' => 'bar', baz: { 'two' => false } }
191
+
192
+ nest[input]
193
+
194
+ expect(input).to eql(output)
195
+ end
196
+
175
197
  it 'returns new hash with an empty hash under a new key when nest-keys are missing' do
176
198
  nest = t(:nest!, :baz, ['foo'])
177
199
 
@@ -1,6 +1,58 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Transproc::Recursion do
4
+ describe '.recursion' do
5
+ let(:original) do
6
+ {
7
+ 'foo' => 'bar',
8
+ 'bar' => {
9
+ 'foo' => 'bar',
10
+ 'bar' => ['foo', 'bar', 'baz'],
11
+ 'baz' => 'foo'
12
+ },
13
+ 'baz' => 'bar'
14
+ }
15
+ end
16
+
17
+ let(:input) { original.dup }
18
+
19
+ let(:output) do
20
+ {
21
+ 'foo' => 'bar',
22
+ 'bar' => {
23
+ 'foo' => 'bar',
24
+ 'bar' => ['foo', 'bar'],
25
+ }
26
+ }
27
+ end
28
+
29
+ context 'when function is non-destructive' do
30
+ let(:map) do
31
+ t(:recursion, -> enum {
32
+ enum.reject { |v| v == 'baz' }
33
+ })
34
+ end
35
+
36
+ it 'applies funtions to all items recursively' do
37
+ expect(map[input]).to eql(output)
38
+ expect(input).to eql(original)
39
+ end
40
+ end
41
+
42
+ context 'when function is destructive' do
43
+ let(:map) do
44
+ t(:recursion, -> enum {
45
+ enum.reject! { |v| v == 'baz' }
46
+ })
47
+ end
48
+
49
+ it 'applies funtions to all items recursively and destructively' do
50
+ expect(map[input]).to eql(output)
51
+ expect(input).to eql(output)
52
+ end
53
+ end
54
+ end
55
+
4
56
  describe '.array_recursion' do
5
57
  let(:original) do
6
58
  [
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe Transproc::Registry do
4
+ before do
5
+ module FooModule
6
+ extend Transproc::Registry
7
+
8
+ def foo(value, prefix)
9
+ [prefix, '_', value].join
10
+ end
11
+ end
12
+
13
+ module BarModule
14
+ include FooModule
15
+
16
+ def bar(*args)
17
+ foo(*args).upcase
18
+ end
19
+ end
20
+
21
+ module BazModule
22
+ extend Transproc::Registry
23
+ end
24
+ end
25
+
26
+ describe '.[]' do
27
+ it 'builds function from the method' do
28
+ fn = ::FooModule[:foo, 'baz']
29
+
30
+ expect(fn['qux']).to eql 'baz_qux'
31
+ end
32
+
33
+ it 'builds function from the proc' do
34
+ fun = -> value, prefix { [prefix, '_', value].join }
35
+ fn = ::FooModule[fun, 'baz']
36
+
37
+ expect(fn['qux']).to eql 'baz_qux'
38
+ end
39
+
40
+ it 'builds function using methods from included modules' do
41
+ fn = ::BarModule[:bar, 'baz']
42
+
43
+ expect(fn['qux']).to eql 'BAZ_QUX'
44
+ end
45
+
46
+ it 'can access methods from included modules directly' do
47
+ fn = ::BarModule[:foo, 'baz']
48
+
49
+ expect(fn['qux']).to eql 'baz_qux'
50
+ end
51
+
52
+ it 'cannot access undefined methods' do
53
+ module ::BarModule
54
+ undef_method :foo
55
+ end
56
+
57
+ expect { ::BarModule[:foo, 'baz'] }.to raise_error(NameError)
58
+ end
59
+ end
60
+
61
+ describe '.uses' do
62
+ it 'forwards methods to another module directly' do
63
+ expect { ::BazModule[:baz, 'baz'] }.to raise_error(NameError)
64
+
65
+ module BazModule
66
+ uses :foo, as: :ffoo, from: FooModule
67
+ uses :bar, from: BarModule
68
+ end
69
+
70
+ ffoo = ::BazModule[:ffoo, 'baz']
71
+ bar = ::BazModule[:bar, 'baz']
72
+
73
+ expect(ffoo['qux']).to eql 'baz_qux'
74
+ expect(bar['qux']).to eql 'BAZ_QUX'
75
+ end
76
+ end
77
+
78
+ describe '#t' do
79
+ it 'is an alias for .[]' do
80
+ module FooModule
81
+ def qux(value, *args)
82
+ t(:foo, *args)[value]
83
+ end
84
+ end
85
+
86
+ fn = ::FooModule[:foo, 'baz']
87
+
88
+ expect(fn['qux']).to eql 'baz_qux'
89
+ end
90
+ end
91
+
92
+ after { Object.send :remove_const, :BazModule }
93
+ after { Object.send :remove_const, :BarModule }
94
+ after { Object.send :remove_const, :FooModule }
95
+ end
@@ -52,13 +52,17 @@ describe Transproc do
52
52
 
53
53
  describe 'handling malformed input' do
54
54
  it 'raises a Transproc::MalformedInputError' do
55
- Transproc.register(:im_dangerous, ->() {
56
- raise ArgumentError, 'sorry, you got some bad apples in your input'
57
- })
58
-
59
55
  expect {
60
- Transproc(:im_dangerous)[hello: 'world']
56
+ Transproc(:to_integer)[{}]
61
57
  }.to raise_error(Transproc::MalformedInputError)
58
+
59
+ begin
60
+ Transproc(:to_integer)[{}]
61
+ rescue Transproc::MalformedInputError => e
62
+ expect(e.message).to include('to_integer')
63
+ expect(e.message).to include("undefined method `to_i'")
64
+ expect(e.backtrace).to eql(e.original_error.backtrace)
65
+ end
62
66
  end
63
67
  end
64
68
  end
@@ -20,5 +20,5 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency 'bundler', '~> 1.7'
22
22
  spec.add_development_dependency 'rake', '~> 10.0'
23
- spec.add_development_dependency 'rspec', '~> 3.1'
23
+ spec.add_development_dependency 'rspec', '~> 3.3'
24
24
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: transproc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-02 00:00:00.000000000 Z
11
+ date: 2015-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.1'
47
+ version: '3.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.1'
54
+ version: '3.3'
55
55
  description: Transform Ruby objects in functional style
56
56
  email:
57
57
  - piotr.solnica@gmail.com
@@ -83,10 +83,12 @@ files:
83
83
  - lib/transproc/functions.rb
84
84
  - lib/transproc/hash.rb
85
85
  - lib/transproc/recursion.rb
86
+ - lib/transproc/registry.rb
86
87
  - lib/transproc/version.rb
87
88
  - rakelib/mutant.rake
88
89
  - rakelib/rubocop.rake
89
90
  - spec/spec_helper.rb
91
+ - spec/support/mutant.rb
90
92
  - spec/unit/array_transformations_spec.rb
91
93
  - spec/unit/class_transformations_spec.rb
92
94
  - spec/unit/coercions_spec.rb
@@ -95,6 +97,7 @@ files:
95
97
  - spec/unit/function_spec.rb
96
98
  - spec/unit/hash_transformations_spec.rb
97
99
  - spec/unit/recursion_spec.rb
100
+ - spec/unit/registry_spec.rb
98
101
  - spec/unit/transproc_spec.rb
99
102
  - transproc.gemspec
100
103
  homepage: http://solnic.github.io/transproc/
@@ -123,6 +126,7 @@ specification_version: 4
123
126
  summary: Transform Ruby objects in functional style
124
127
  test_files:
125
128
  - spec/spec_helper.rb
129
+ - spec/support/mutant.rb
126
130
  - spec/unit/array_transformations_spec.rb
127
131
  - spec/unit/class_transformations_spec.rb
128
132
  - spec/unit/coercions_spec.rb
@@ -131,4 +135,5 @@ test_files:
131
135
  - spec/unit/function_spec.rb
132
136
  - spec/unit/hash_transformations_spec.rb
133
137
  - spec/unit/recursion_spec.rb
138
+ - spec/unit/registry_spec.rb
134
139
  - spec/unit/transproc_spec.rb