transproc 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +13 -0
- data/CHANGELOG.md +16 -0
- data/README.md +35 -5
- data/Rakefile +4 -1
- data/lib/transproc.rb +3 -20
- data/lib/transproc/all.rb +5 -0
- data/lib/transproc/array.rb +28 -0
- data/lib/transproc/coercions.rb +25 -0
- data/lib/transproc/composer.rb +33 -0
- data/lib/transproc/function.rb +20 -0
- data/lib/transproc/hash.rb +31 -3
- data/lib/transproc/version.rb +1 -1
- data/spec/integration/array_spec.rb +98 -0
- data/spec/integration/coercions_spec.rb +44 -2
- data/spec/integration/composer_spec.rb +20 -0
- data/spec/integration/hash_spec.rb +121 -0
- data/spec/spec_helper.rb +5 -91
- data/transproc.gemspec +1 -1
- metadata +14 -4
- data/spec/integration/hash_mapping_spec.rb +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 191351a547ec40a988d4948a669c8a19a9d9e7b5
|
4
|
+
data.tar.gz: 6fa7367728d8b2738b0cb8385bb5f95711952530
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fed4a175a284af002c5a7d960512f06fa315a4997c74cc2512edbe491b0309b0e66370c89a4a3ebf56f1910aec2791aa2cfbbcdb5407070654443208976ce32e
|
7
|
+
data.tar.gz: 9060a11216f66bf85cadf56a60503e3a21878358641a4680aa35624077ff181bb9946b0e6c6cf0ac6c9b83a17e9719dadbef9d1e3760fd46a770ae967d3d5a16
|
data/.travis.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
language: ruby
|
2
|
+
env:
|
3
|
+
- CODECLIMATE_REPO_TOKEN=aead71de2239048f830499462c54b57dfc646f1d56ad5dcbbc3469a6ebaf97ca
|
4
|
+
script: "bundle exec rake spec"
|
5
|
+
rvm:
|
6
|
+
- 2.0
|
7
|
+
- 2.1
|
8
|
+
- rbx-2
|
9
|
+
- jruby
|
10
|
+
- ruby-head
|
11
|
+
matrix:
|
12
|
+
allow_failures:
|
13
|
+
- rvm: ruby-head
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
## v0.1.0 to-be-released
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* added bang-method equivalents to all functions (solnic)
|
6
|
+
* group and wrap array transformations (solnic)
|
7
|
+
* date, datetime and time coercions (solnic)
|
8
|
+
* numeric coercions (solnic)
|
9
|
+
* boolean coercions (solnic)
|
10
|
+
* [hash] `:nest` which wraps a set of keys under a new key (solnic)
|
11
|
+
|
12
|
+
[Compare v0.0.1...master](https://github.com/solnic/transproc/compare/v0.0.1...master)
|
13
|
+
|
14
|
+
## v0.0.1 2014-12-24
|
15
|
+
|
16
|
+
First public release \o/
|
data/README.md
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
+
[gem]: https://rubygems.org/gems/transproc
|
2
|
+
[travis]: https://travis-ci.org/solnic/transproc
|
3
|
+
[gemnasium]: https://gemnasium.com/solnic/transproc
|
4
|
+
[codeclimate]: https://codeclimate.com/github/solnic/transproc
|
5
|
+
[coveralls]: https://coveralls.io/r/solnic/transproc
|
6
|
+
[inchpages]: http://inch-ci.org/github/solnic/transproc
|
7
|
+
|
1
8
|
# Transproc
|
2
9
|
|
3
|
-
|
10
|
+
[![Gem Version](https://badge.fury.io/rb/transproc.svg)][gem]
|
11
|
+
[![Build Status](https://travis-ci.org/solnic/transproc.svg?branch=master)][travis]
|
12
|
+
[![Dependency Status](https://gemnasium.com/solnic/transproc.png)][gemnasium]
|
13
|
+
[![Code Climate](https://codeclimate.com/github/solnic/transproc/badges/gpa.svg)][codeclimate]
|
14
|
+
[![Test Coverage](https://codeclimate.com/github/solnic/transproc/badges/coverage.svg)][codeclimate]
|
15
|
+
[![Inline docs](http://inch-ci.org/github/solnic/transproc.svg?branch=master)][inchpages]
|
4
16
|
|
5
|
-
|
17
|
+
Functional transformations for Ruby. It's currently used as one of the data
|
18
|
+
mapping backends in [Ruby Object Mapper](http://rom-rb.org).
|
6
19
|
|
7
20
|
## Installation
|
8
21
|
|
@@ -23,19 +36,36 @@ Or install it yourself as:
|
|
23
36
|
## Usage
|
24
37
|
|
25
38
|
``` ruby
|
26
|
-
require 'transproc/
|
39
|
+
require 'transproc/all'
|
27
40
|
|
28
41
|
# compose transformation functions
|
29
|
-
transformation = Transproc(:symbolize_keys) + Transproc(:
|
42
|
+
transformation = Transproc(:symbolize_keys) + Transproc(:map_hash, user_name: :name))
|
30
43
|
|
31
44
|
# call the function
|
45
|
+
transformation['user_name' => 'Jane']
|
46
|
+
# => {:name=>"Jane"}
|
47
|
+
|
48
|
+
# or using a helper (no, it's not a good idea to include it here :))
|
49
|
+
include Transproc::Composer
|
50
|
+
|
51
|
+
transformation = compose do |fns|
|
52
|
+
fns << t(:symbolize_keys) << t(:map_hash, user_name: :name)
|
53
|
+
end
|
54
|
+
|
32
55
|
transformation['user_name' => 'Jane']
|
33
56
|
# => {:name=>"Jane"}
|
34
57
|
```
|
35
58
|
|
59
|
+
## Credits
|
60
|
+
|
61
|
+
This project is inspired by the work of following people:
|
62
|
+
|
63
|
+
* [Markus Schirp](https://github.com/mbj) and [morpher](https://github.com/mbj/morpher) project
|
64
|
+
* [Josep M. Bach](https://github.com/txus) and [kleisli](https://github.com/txus/kleisli) project
|
65
|
+
|
36
66
|
## Contributing
|
37
67
|
|
38
|
-
1. Fork it ( https://github.com/
|
68
|
+
1. Fork it ( https://github.com/solnic/transproc/fork )
|
39
69
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
40
70
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
41
71
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/Rakefile
CHANGED
data/lib/transproc.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require 'transproc/version'
|
2
|
+
require 'transproc/function'
|
3
|
+
require 'transproc/composer'
|
2
4
|
|
3
5
|
module Transproc
|
4
6
|
def self.register(*args, &block)
|
@@ -13,25 +15,6 @@ module Transproc
|
|
13
15
|
def self.[](name)
|
14
16
|
functions.fetch(name)
|
15
17
|
end
|
16
|
-
|
17
|
-
class Function
|
18
|
-
attr_reader :fn, :args
|
19
|
-
|
20
|
-
def initialize(fn, args = [])
|
21
|
-
@fn = fn
|
22
|
-
@args = args
|
23
|
-
end
|
24
|
-
|
25
|
-
def call(value)
|
26
|
-
fn[value, *args]
|
27
|
-
end
|
28
|
-
alias_method :[], :call
|
29
|
-
|
30
|
-
def compose(other)
|
31
|
-
self.class.new(-> value { other[fn[value]] })
|
32
|
-
end
|
33
|
-
alias_method :+, :compose
|
34
|
-
end
|
35
18
|
end
|
36
19
|
|
37
20
|
def Transproc(fn, *args)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Transproc
|
2
|
+
register(:map_array) do |array, *fns|
|
3
|
+
Transproc(:map_array!, *fns)[array.dup]
|
4
|
+
end
|
5
|
+
|
6
|
+
register(:map_array!) do |array, *fns|
|
7
|
+
array.map! { |value| fns.reduce(:+)[value] }
|
8
|
+
end
|
9
|
+
|
10
|
+
register(:wrap) do |array, key, keys|
|
11
|
+
Transproc(:map_array, Transproc(:nest, key, keys))[array]
|
12
|
+
end
|
13
|
+
|
14
|
+
register(:group) do |array, key, keys|
|
15
|
+
names = nil
|
16
|
+
|
17
|
+
array
|
18
|
+
.group_by { |hash|
|
19
|
+
names ||= hash.keys - keys
|
20
|
+
Hash[names.zip(hash.values_at(*names))]
|
21
|
+
}
|
22
|
+
.map { |root, children|
|
23
|
+
children.map! { |child| Hash[keys.zip(child.values_at(*keys))] }
|
24
|
+
children.select! { |child| child.values.any? }
|
25
|
+
root.merge(key => children)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
data/lib/transproc/coercions.rb
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
require 'date'
|
2
|
+
require 'bigdecimal'
|
3
|
+
require 'bigdecimal/util'
|
2
4
|
|
3
5
|
module Transproc
|
6
|
+
TRUE_VALUES = [true, 1, '1', 'on', 't', 'true', 'y', 'yes'].freeze
|
7
|
+
FALSE_VALUES = [false, 0, '0', 'off', 'f', 'false', 'n', 'no'].freeze
|
8
|
+
|
9
|
+
BOOLEAN_MAP = Hash[
|
10
|
+
TRUE_VALUES.product([true]) + FALSE_VALUES.product([false])
|
11
|
+
].freeze
|
12
|
+
|
4
13
|
register(:to_string) do |value|
|
5
14
|
value.to_s
|
6
15
|
end
|
@@ -13,7 +22,23 @@ module Transproc
|
|
13
22
|
value.to_f
|
14
23
|
end
|
15
24
|
|
25
|
+
register(:to_decimal) do |value|
|
26
|
+
value.to_d
|
27
|
+
end
|
28
|
+
|
29
|
+
register(:to_boolean) do |value|
|
30
|
+
BOOLEAN_MAP.fetch(value)
|
31
|
+
end
|
32
|
+
|
16
33
|
register(:to_date) do |value|
|
17
34
|
Date.parse(value)
|
18
35
|
end
|
36
|
+
|
37
|
+
register(:to_time) do |value|
|
38
|
+
Time.parse(value)
|
39
|
+
end
|
40
|
+
|
41
|
+
register(:to_datetime) do |value|
|
42
|
+
DateTime.parse(value)
|
43
|
+
end
|
19
44
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Transproc
|
2
|
+
module Composer
|
3
|
+
|
4
|
+
class Factory
|
5
|
+
attr_reader :fns, :default
|
6
|
+
|
7
|
+
def initialize(default = nil)
|
8
|
+
@fns = []
|
9
|
+
@default = default
|
10
|
+
end
|
11
|
+
|
12
|
+
def <<(other)
|
13
|
+
fns.concat(Array(other).compact)
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_fn
|
18
|
+
fns.reduce(:+) || default
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def t(*args)
|
23
|
+
Transproc(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def compose(default = nil)
|
27
|
+
factory = Factory.new(default)
|
28
|
+
yield(factory)
|
29
|
+
factory.to_fn
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Transproc
|
2
|
+
class Function
|
3
|
+
attr_reader :fn, :args
|
4
|
+
|
5
|
+
def initialize(fn, args = [])
|
6
|
+
@fn = fn
|
7
|
+
@args = args
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(value)
|
11
|
+
fn[value, *args]
|
12
|
+
end
|
13
|
+
alias_method :[], :call
|
14
|
+
|
15
|
+
def compose(other)
|
16
|
+
self.class.new(-> *result { other[fn[*result]] }, args)
|
17
|
+
end
|
18
|
+
alias_method :+, :compose
|
19
|
+
end
|
20
|
+
end
|
data/lib/transproc/hash.rb
CHANGED
@@ -1,9 +1,37 @@
|
|
1
1
|
module Transproc
|
2
2
|
register(:symbolize_keys) do |hash|
|
3
|
-
|
3
|
+
Transproc(:symbolize_keys!)[hash.dup]
|
4
4
|
end
|
5
5
|
|
6
|
-
register(:
|
7
|
-
|
6
|
+
register(:symbolize_keys!) do |hash|
|
7
|
+
hash.keys.each { |key| hash[key.to_sym] = hash.delete(key) }
|
8
|
+
hash
|
9
|
+
end
|
10
|
+
|
11
|
+
register(:map_hash) do |hash, mapping|
|
12
|
+
Transproc(:map_hash!, mapping)[hash.dup]
|
13
|
+
end
|
14
|
+
|
15
|
+
register(:map_hash!) do |hash, mapping|
|
16
|
+
mapping.each { |k, v| hash[v] = hash.delete(k) }
|
17
|
+
hash
|
18
|
+
end
|
19
|
+
|
20
|
+
register(:map_key) do |hash, key, fn|
|
21
|
+
hash.merge(key => fn[hash[key]])
|
22
|
+
end
|
23
|
+
|
24
|
+
register(:map_key!) do |hash, key, fn|
|
25
|
+
hash.update(key => fn[hash[key]])
|
26
|
+
end
|
27
|
+
|
28
|
+
register(:nest) do |hash, key, keys|
|
29
|
+
Transproc(:nest!, key, keys)[hash.dup]
|
30
|
+
end
|
31
|
+
|
32
|
+
register(:nest!) do |hash, root, keys|
|
33
|
+
child = Hash[keys.zip(keys.map { |key| hash.delete(key) })]
|
34
|
+
|
35
|
+
hash.update(root => child.values.any? ? child : nil)
|
8
36
|
end
|
9
37
|
end
|
data/lib/transproc/version.rb
CHANGED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Array transformations with Transproc' do
|
4
|
+
describe 'map_array' do
|
5
|
+
it 'applies funtions to all values' do
|
6
|
+
map = Transproc(:map_array, Transproc(:symbolize_keys))
|
7
|
+
|
8
|
+
original = [
|
9
|
+
{ 'name' => 'Jane', 'title' => 'One' },
|
10
|
+
{ 'name' => 'Jane', 'title' => 'Two' }
|
11
|
+
]
|
12
|
+
|
13
|
+
input = original
|
14
|
+
|
15
|
+
output = [
|
16
|
+
{ name: 'Jane', title: 'One' },
|
17
|
+
{ name: 'Jane', title: 'Two' }
|
18
|
+
]
|
19
|
+
|
20
|
+
expect(map[input]).to eql(output)
|
21
|
+
expect(input).to eql(original)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'map_array!' do
|
26
|
+
it 'updates array with the result of the function applied to each value' do
|
27
|
+
map = Transproc(:map_array!, Transproc(:symbolize_keys))
|
28
|
+
|
29
|
+
input = [
|
30
|
+
{ 'name' => 'Jane', 'title' => 'One' },
|
31
|
+
{ 'name' => 'Jane', 'title' => 'Two' }
|
32
|
+
]
|
33
|
+
|
34
|
+
output = [
|
35
|
+
{ name: 'Jane', title: 'One' },
|
36
|
+
{ name: 'Jane', title: 'Two' }
|
37
|
+
]
|
38
|
+
|
39
|
+
map[input]
|
40
|
+
|
41
|
+
expect(input).to eql(output)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'wrap' do
|
46
|
+
it 'returns a new array with wrapped hashes' do
|
47
|
+
wrap = Transproc(:wrap, :task, [:title])
|
48
|
+
|
49
|
+
input = [{ name: 'Jane', title: 'One' }]
|
50
|
+
output = [{ name: 'Jane', task: { title: 'One' } }]
|
51
|
+
|
52
|
+
expect(wrap[input]).to eql(output)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'returns a array new with deeply wrapped hashes' do
|
56
|
+
wrap =
|
57
|
+
Transproc(
|
58
|
+
:map_array,
|
59
|
+
Transproc(:nest, :user, [:name, :title]),
|
60
|
+
Transproc(:map_key, :user, Transproc(:nest, :task, [:title]))
|
61
|
+
)
|
62
|
+
|
63
|
+
input = [{ name: 'Jane', title: 'One' }]
|
64
|
+
output = [{ user: { name: 'Jane', task: { title: 'One' } } }]
|
65
|
+
|
66
|
+
expect(wrap[input]).to eql(output)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'group' do
|
71
|
+
it 'returns a new array with grouped hashes' do
|
72
|
+
group = Transproc(:group, :tasks, [:title])
|
73
|
+
|
74
|
+
input = [{ name: 'Jane', title: 'One' }, { name: 'Jane', title: 'Two' }]
|
75
|
+
output = [{ name: 'Jane', tasks: [{ title: 'One' }, { title: 'Two' }] }]
|
76
|
+
|
77
|
+
expect(group[input]).to eql(output)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'composition' do
|
82
|
+
it 'allows composing transformations' do
|
83
|
+
map = Transproc(:map_array, Transproc(:symbolize_keys))
|
84
|
+
group = Transproc(:group, :tasks, [:title])
|
85
|
+
|
86
|
+
input = [
|
87
|
+
{ 'name' => 'Jane', 'title' => 'One' },
|
88
|
+
{ 'name' => 'Jane', 'title' => 'Two' }
|
89
|
+
]
|
90
|
+
|
91
|
+
output = [{ name: 'Jane', tasks: [{ title: 'One' }, { title: 'Two' }] }]
|
92
|
+
|
93
|
+
transformation = map + group
|
94
|
+
|
95
|
+
expect(transformation[input]).to eql(output)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
require 'transproc/coercions'
|
4
|
-
|
5
3
|
describe 'Transproc / Coercions' do
|
6
4
|
describe 'to_string' do
|
7
5
|
it 'turns integer into a string' do
|
@@ -25,10 +23,54 @@ describe 'Transproc / Coercions' do
|
|
25
23
|
end
|
26
24
|
end
|
27
25
|
|
26
|
+
describe 'to_decimal' do
|
27
|
+
it 'turns string into a decimal' do
|
28
|
+
expect(Transproc(:to_decimal)['1.251']).to eql(BigDecimal('1.251'))
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'turns float into a decimal' do
|
32
|
+
expect(Transproc(:to_decimal)[1.251]).to eql(BigDecimal('1.251'))
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'turns integer into a decimal' do
|
36
|
+
expect(Transproc(:to_decimal)[1]).to eql(BigDecimal('1.0'))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
28
40
|
describe 'to_date' do
|
29
41
|
it 'turns string into a date' do
|
30
42
|
date = Date.new(1983, 11, 18)
|
31
43
|
expect(Transproc(:to_date)['18th, November 1983']).to eql(date)
|
32
44
|
end
|
33
45
|
end
|
46
|
+
|
47
|
+
describe 'to_time' do
|
48
|
+
it 'turns string into a time object' do
|
49
|
+
time = Time.new(2012, 1, 23, 11, 7, 7)
|
50
|
+
expect(Transproc(:to_time)['2012-01-23 11:07:07']).to eql(time)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'to_datetime' do
|
55
|
+
it 'turns string into a date' do
|
56
|
+
datetime = DateTime.new(2012, 1, 23, 11, 7, 7)
|
57
|
+
expect(Transproc(:to_datetime)['2012-01-23 11:07:07']).to eql(datetime)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'to_boolean' do
|
62
|
+
subject(:coercer) { Transproc(:to_boolean) }
|
63
|
+
|
64
|
+
Transproc::TRUE_VALUES.each do |value|
|
65
|
+
it "turns #{value.inspect} to true" do
|
66
|
+
expect(coercer[value]).to be(true)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
Transproc::FALSE_VALUES.each do |value|
|
71
|
+
it "turns #{value.inspect} to false" do
|
72
|
+
expect(coercer[value]).to be(false)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
34
76
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Transproc::Composer do
|
4
|
+
subject(:object) do
|
5
|
+
Class.new do
|
6
|
+
include Transproc::Composer
|
7
|
+
|
8
|
+
def fn
|
9
|
+
compose do |fns|
|
10
|
+
fns << t(:map_array, t(:symbolize_keys)) <<
|
11
|
+
t(:map_array, t(:map_key, :age, t(:to_integer)))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end.new
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'allows composing functions' do
|
18
|
+
expect(object.fn[[{ 'age' => '12' }]]).to eql([{ age: 12 }])
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Hash mapping with Transproc' do
|
4
|
+
describe 'symbolize_keys' do
|
5
|
+
it 'returns a new hash with symbolized keys' do
|
6
|
+
symbolize_keys = Transproc(:symbolize_keys)
|
7
|
+
|
8
|
+
input = { 'foo' => 'bar' }
|
9
|
+
output = { foo: 'bar' }
|
10
|
+
|
11
|
+
expect(symbolize_keys[input]).to eql(output)
|
12
|
+
expect(input).to eql('foo' => 'bar')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'symbolize_keys!' do
|
17
|
+
it 'returns updated hash with symbolized keys' do
|
18
|
+
symbolize_keys = Transproc(:symbolize_keys!)
|
19
|
+
|
20
|
+
input = { 'foo' => 'bar' }
|
21
|
+
output = { foo: 'bar' }
|
22
|
+
|
23
|
+
symbolize_keys[input]
|
24
|
+
|
25
|
+
expect(input).to eql(output)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'nest!' do
|
30
|
+
it 'returns new hash with keys nested under a new key' do
|
31
|
+
nest = Transproc(:nest!, :baz, ['foo'])
|
32
|
+
|
33
|
+
input = { 'foo' => 'bar' }
|
34
|
+
output = { baz: { 'foo' => 'bar' } }
|
35
|
+
|
36
|
+
nest[input]
|
37
|
+
|
38
|
+
expect(input).to eql(output)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'map_hash' do
|
43
|
+
it 'returns a new hash with applied functions' do
|
44
|
+
map = Transproc(:map_hash, 'foo' => :foo)
|
45
|
+
|
46
|
+
input = { 'foo' => 'bar', :bar => 'baz' }
|
47
|
+
output = { foo: 'bar', bar: 'baz' }
|
48
|
+
|
49
|
+
expect(map[input]).to eql(output)
|
50
|
+
expect(input).to eql('foo' => 'bar', :bar => 'baz')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'map_hash!' do
|
55
|
+
it 'returns updated hash with applied functions' do
|
56
|
+
map = Transproc(:map_hash!, 'foo' => :foo)
|
57
|
+
|
58
|
+
input = { 'foo' => 'bar', :bar => 'baz' }
|
59
|
+
output = { foo: 'bar', bar: 'baz' }
|
60
|
+
|
61
|
+
map[input]
|
62
|
+
|
63
|
+
expect(input).to eql(output)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'map_key' do
|
68
|
+
it 'applies function to value under specified key' do
|
69
|
+
transformation = Transproc(:map_key, :user, Transproc(:symbolize_keys))
|
70
|
+
|
71
|
+
input = { user: { 'name' => 'Jane' } }
|
72
|
+
output = { user: { name: 'Jane' } }
|
73
|
+
|
74
|
+
expect(transformation[input]).to eql(output)
|
75
|
+
expect(input).to eql(user: { 'name' => 'Jane' })
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'map_key!' do
|
80
|
+
it 'applies function to value under specified key' do
|
81
|
+
transformation = Transproc(:map_key!, :user, Transproc(:symbolize_keys))
|
82
|
+
|
83
|
+
input = { user: { 'name' => 'Jane' } }
|
84
|
+
output = { user: { name: 'Jane' } }
|
85
|
+
|
86
|
+
transformation[input]
|
87
|
+
|
88
|
+
expect(input).to eql(output)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe 'nested transform' do
|
93
|
+
it 'applies functions to nested hashes' do
|
94
|
+
symbolize_keys = Transproc(:symbolize_keys)
|
95
|
+
map_user_key = Transproc(:map_key, :user, symbolize_keys)
|
96
|
+
|
97
|
+
transformation = symbolize_keys + map_user_key
|
98
|
+
|
99
|
+
input = { 'user' => { 'name' => 'Jane' } }
|
100
|
+
output = { user: { name: 'Jane' } }
|
101
|
+
|
102
|
+
expect(transformation[input]).to eql(output)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe 'combining transformations' do
|
107
|
+
it 'applies functions to the hash' do
|
108
|
+
symbolize_keys = Transproc(:symbolize_keys)
|
109
|
+
map = Transproc(:map_hash, user_name: :name, user_email: :email)
|
110
|
+
|
111
|
+
transformation = symbolize_keys + map
|
112
|
+
|
113
|
+
input = { 'user_name' => 'Jade', 'user_email' => 'jade@doe.org' }
|
114
|
+
output = { name: 'Jade', email: 'jade@doe.org' }
|
115
|
+
|
116
|
+
result = transformation[input]
|
117
|
+
|
118
|
+
expect(result).to eql(output)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,92 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
# This file was generated by the `rspec --init` command. Conventionally, all
|
5
|
-
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
6
|
-
# The generated `.rspec` file contains `--require spec_helper` which will cause this
|
7
|
-
# file to always be loaded, without a need to explicitly require it in any files.
|
8
|
-
#
|
9
|
-
# Given that it is always loaded, you are encouraged to keep this file as
|
10
|
-
# light-weight as possible. Requiring heavyweight dependencies from this file
|
11
|
-
# will add to the boot time of your test suite on EVERY test run, even for an
|
12
|
-
# individual file that may not need all of that loaded. Instead, consider making
|
13
|
-
# a separate helper file that requires the additional dependencies and performs
|
14
|
-
# the additional setup, and require it from the spec files that actually need it.
|
15
|
-
#
|
16
|
-
# The `.rspec` file also contains a few flags that are not defaults but that
|
17
|
-
# users commonly want.
|
18
|
-
#
|
19
|
-
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
20
|
-
RSpec.configure do |config|
|
21
|
-
# rspec-expectations config goes here. You can use an alternate
|
22
|
-
# assertion/expectation library such as wrong or the stdlib/minitest
|
23
|
-
# assertions if you prefer.
|
24
|
-
config.expect_with :rspec do |expectations|
|
25
|
-
# This option will default to `true` in RSpec 4. It makes the `description`
|
26
|
-
# and `failure_message` of custom matchers include text for helper methods
|
27
|
-
# defined using `chain`, e.g.:
|
28
|
-
# be_bigger_than(2).and_smaller_than(4).description
|
29
|
-
# # => "be bigger than 2 and smaller than 4"
|
30
|
-
# ...rather than:
|
31
|
-
# # => "be bigger than 2"
|
32
|
-
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
33
|
-
end
|
34
|
-
|
35
|
-
# rspec-mocks config goes here. You can use an alternate test double
|
36
|
-
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
37
|
-
config.mock_with :rspec do |mocks|
|
38
|
-
# Prevents you from mocking or stubbing a method that does not exist on
|
39
|
-
# a real object. This is generally recommended, and will default to
|
40
|
-
# `true` in RSpec 4.
|
41
|
-
mocks.verify_partial_doubles = true
|
42
|
-
end
|
43
|
-
|
44
|
-
# The settings below are suggested to provide a good initial experience
|
45
|
-
# with RSpec, but feel free to customize to your heart's content.
|
46
|
-
=begin
|
47
|
-
# These two settings work together to allow you to limit a spec run
|
48
|
-
# to individual examples or groups you care about by tagging them with
|
49
|
-
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
50
|
-
# get run.
|
51
|
-
config.filter_run :focus
|
52
|
-
config.run_all_when_everything_filtered = true
|
53
|
-
|
54
|
-
# Limits the available syntax to the non-monkey patched syntax that is recommended.
|
55
|
-
# For more details, see:
|
56
|
-
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
57
|
-
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
58
|
-
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
|
59
|
-
config.disable_monkey_patching!
|
60
|
-
|
61
|
-
# This setting enables warnings. It's recommended, but in some cases may
|
62
|
-
# be too noisy due to issues in dependencies.
|
63
|
-
config.warnings = true
|
64
|
-
|
65
|
-
# Many RSpec users commonly either run the entire suite or an individual
|
66
|
-
# file, and it's useful to allow more verbose output when running an
|
67
|
-
# individual spec file.
|
68
|
-
if config.files_to_run.one?
|
69
|
-
# Use the documentation formatter for detailed output,
|
70
|
-
# unless a formatter has already been configured
|
71
|
-
# (e.g. via a command-line flag).
|
72
|
-
config.default_formatter = 'doc'
|
73
|
-
end
|
74
|
-
|
75
|
-
# Print the 10 slowest examples and example groups at the
|
76
|
-
# end of the spec run, to help surface which specs are running
|
77
|
-
# particularly slow.
|
78
|
-
config.profile_examples = 10
|
79
|
-
|
80
|
-
# Run specs in random order to surface order dependencies. If you find an
|
81
|
-
# order dependency and want to debug it, you can fix the order by providing
|
82
|
-
# the seed, which is printed after each run.
|
83
|
-
# --seed 1234
|
84
|
-
config.order = :random
|
85
|
-
|
86
|
-
# Seed global randomization in this process using the `--seed` CLI option.
|
87
|
-
# Setting this allows you to use `--seed` to deterministically reproduce
|
88
|
-
# test failures related to randomization by passing the same `--seed` value
|
89
|
-
# as the one that triggered the failure.
|
90
|
-
Kernel.srand config.seed
|
91
|
-
=end
|
1
|
+
if RUBY_ENGINE == "rbx"
|
2
|
+
require "codeclimate-test-reporter"
|
3
|
+
CodeClimate::TestReporter.start
|
92
4
|
end
|
5
|
+
|
6
|
+
require 'transproc/all'
|
data/transproc.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'transproc/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "transproc"
|
8
|
-
spec.version = Transproc::VERSION
|
8
|
+
spec.version = Transproc::VERSION.dup
|
9
9
|
spec.authors = ["Piotr Solnica"]
|
10
10
|
spec.email = ["piotr.solnica@gmail.com"]
|
11
11
|
spec.summary = %q{Experimental functional transformations for Ruby}
|
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.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -61,17 +61,25 @@ extra_rdoc_files: []
|
|
61
61
|
files:
|
62
62
|
- ".gitignore"
|
63
63
|
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
|
+
- CHANGELOG.md
|
64
66
|
- Gemfile
|
65
67
|
- Guardfile
|
66
68
|
- LICENSE.txt
|
67
69
|
- README.md
|
68
70
|
- Rakefile
|
69
71
|
- lib/transproc.rb
|
72
|
+
- lib/transproc/all.rb
|
73
|
+
- lib/transproc/array.rb
|
70
74
|
- lib/transproc/coercions.rb
|
75
|
+
- lib/transproc/composer.rb
|
76
|
+
- lib/transproc/function.rb
|
71
77
|
- lib/transproc/hash.rb
|
72
78
|
- lib/transproc/version.rb
|
79
|
+
- spec/integration/array_spec.rb
|
73
80
|
- spec/integration/coercions_spec.rb
|
74
|
-
- spec/integration/
|
81
|
+
- spec/integration/composer_spec.rb
|
82
|
+
- spec/integration/hash_spec.rb
|
75
83
|
- spec/integration/transproc_spec.rb
|
76
84
|
- spec/spec_helper.rb
|
77
85
|
- transproc.gemspec
|
@@ -100,8 +108,10 @@ signing_key:
|
|
100
108
|
specification_version: 4
|
101
109
|
summary: Experimental functional transformations for Ruby
|
102
110
|
test_files:
|
111
|
+
- spec/integration/array_spec.rb
|
103
112
|
- spec/integration/coercions_spec.rb
|
104
|
-
- spec/integration/
|
113
|
+
- spec/integration/composer_spec.rb
|
114
|
+
- spec/integration/hash_spec.rb
|
105
115
|
- spec/integration/transproc_spec.rb
|
106
116
|
- spec/spec_helper.rb
|
107
117
|
has_rdoc:
|
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
require 'transproc/hash'
|
4
|
-
|
5
|
-
describe 'Hash mapping with Transproc' do
|
6
|
-
describe 'symbolize_keys' do
|
7
|
-
it 'returns a new hash with symbolized keys' do
|
8
|
-
symbolize_keys = Transproc(:symbolize_keys)
|
9
|
-
|
10
|
-
input = { 'foo' => 'bar' }
|
11
|
-
output = { foo: 'bar' }
|
12
|
-
|
13
|
-
expect(symbolize_keys[input]).to eql(output)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe 'map' do
|
18
|
-
it 'returns a new hash with applied functions' do
|
19
|
-
map = Transproc(:map, 'foo' => :foo)
|
20
|
-
|
21
|
-
input = { 'foo' => 'bar' }
|
22
|
-
output = { foo: 'bar' }
|
23
|
-
|
24
|
-
expect(map[input]).to eql(output)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe 'combining transformations' do
|
29
|
-
it 'applies functions to the hash' do
|
30
|
-
symbolize_keys = Transproc(:symbolize_keys)
|
31
|
-
map = Transproc(:map, user_name: :name, user_email: :email)
|
32
|
-
|
33
|
-
transformation = symbolize_keys + map
|
34
|
-
|
35
|
-
input = { 'user_name' => 'Jade', 'user_email' => 'jade@doe.org' }
|
36
|
-
output = { name: 'Jade', email: 'jade@doe.org' }
|
37
|
-
|
38
|
-
result = transformation[input]
|
39
|
-
|
40
|
-
expect(result).to eql(output)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|