transproc 0.2.3 → 0.2.4

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 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