morfo 0.3.0 → 0.4.0
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 +4 -4
- data/CONTRIBUTING.md +1 -1
- data/Gemfile +11 -11
- data/Guardfile +2 -2
- data/README.md +180 -64
- data/Rakefile +2 -2
- data/benchmarks/data.rb +10 -10
- data/benchmarks/run.rb +7 -7
- data/lib/morfo.rb +6 -15
- data/lib/morfo/builder.rb +34 -0
- data/lib/morfo/tools.rb +34 -0
- data/lib/morfo/version.rb +1 -1
- data/morfo.gemspec +14 -13
- data/spec/lib/morfo/builder_spec.rb +114 -0
- data/spec/lib/morfo/tools_spec.rb +91 -0
- data/spec/lib/morfo_spec.rb +51 -230
- data/spec/spec_helper.rb +7 -5
- data/spec/support/shared_context.rb +34 -0
- data/spec/support/shared_examples.rb +248 -0
- metadata +27 -3
data/lib/morfo/tools.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Morfo
|
2
|
+
module Tools
|
3
|
+
class FlattenHashKeys
|
4
|
+
attr_reader :input_hash
|
5
|
+
|
6
|
+
def initialize(input_hash)
|
7
|
+
@input_hash = input_hash.dup.freeze
|
8
|
+
end
|
9
|
+
|
10
|
+
def flatten
|
11
|
+
input_hash.inject({}) do |result_hash, (key, value)|
|
12
|
+
inner_hash = false
|
13
|
+
if value.is_a?(Hash)
|
14
|
+
inner_hash = true
|
15
|
+
value.each do |inner_key, inner_value|
|
16
|
+
if inner_value.is_a?(Hash)
|
17
|
+
inner_hash = true
|
18
|
+
end
|
19
|
+
result_hash.merge!("#{key}.#{inner_key}".to_sym => inner_value)
|
20
|
+
end
|
21
|
+
else
|
22
|
+
result_hash.merge!(key.to_sym => value)
|
23
|
+
end
|
24
|
+
|
25
|
+
if inner_hash
|
26
|
+
FlattenHashKeys.new(result_hash).flatten
|
27
|
+
else
|
28
|
+
result_hash
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/morfo/version.rb
CHANGED
data/morfo.gemspec
CHANGED
@@ -1,27 +1,28 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "morfo/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = "morfo"
|
8
8
|
spec.version = Morfo::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
9
|
+
spec.authors = ["Leif Gensert"]
|
10
|
+
spec.email = ["leif@propertybase.com"]
|
11
11
|
spec.description = %q{This gem provides a DSL for converting one hash into another}
|
12
12
|
spec.summary = %q{Inspired by ActiveImporter, this gem generically converts an array of hashes}
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency
|
22
|
-
spec.add_dependency
|
23
|
-
spec.add_dependency
|
21
|
+
spec.add_dependency "rake"
|
22
|
+
spec.add_dependency "json"
|
23
|
+
spec.add_dependency "activesupport", ">= 3.2"
|
24
|
+
spec.add_dependency "rubysl" if RUBY_ENGINE == "rbx"
|
24
25
|
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rspec", ">= 2.14", "< 4.0"
|
27
28
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Morfo::Builder do
|
4
|
+
describe "#build" do
|
5
|
+
subject { described_class.new(definitions) }
|
6
|
+
|
7
|
+
let(:definitions) do
|
8
|
+
[
|
9
|
+
{
|
10
|
+
field: :tv_show_title,
|
11
|
+
from: :title,
|
12
|
+
}
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:morfer) { subject.build }
|
17
|
+
|
18
|
+
it "has a morf method" do
|
19
|
+
expect(morfer).to respond_to(:morf)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "has a morf_single method" do
|
23
|
+
expect(morfer).to respond_to(:morf_single)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "on the fly morfers" do
|
28
|
+
subject { described_class.new(definitions).build }
|
29
|
+
|
30
|
+
it_behaves_like "a 1 to 1 morfer" do
|
31
|
+
let(:definitions) do
|
32
|
+
[
|
33
|
+
{ field: :tv_show_title, from: :title }
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it_behaves_like "a 1 to many morfer" do
|
39
|
+
let(:definitions) do
|
40
|
+
[
|
41
|
+
{ field: :title, from: :title },
|
42
|
+
{ field: :also_title, from: :title },
|
43
|
+
]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it_behaves_like "a static morfer" do
|
48
|
+
let(:definitions) do
|
49
|
+
[
|
50
|
+
{ field: :new_title, calculated: "Static Title" },
|
51
|
+
]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it_behaves_like "a calculating morfer" do
|
56
|
+
let(:definitions) do
|
57
|
+
[
|
58
|
+
{ field: :title_with_channel, calculated: "%{title}, (%{channel})" },
|
59
|
+
]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it_behaves_like "a 1 to 1 morfer with transformation" do
|
64
|
+
let(:definitions) do
|
65
|
+
[
|
66
|
+
{ field: :title, from: :title, transformed: "%{value} and Zombies" }
|
67
|
+
]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it_behaves_like "a morfer with nested source" do
|
72
|
+
subject(:valid_path) do
|
73
|
+
described_class.new(
|
74
|
+
[
|
75
|
+
{ field: :rating, from: [:ratings, :imdb] }
|
76
|
+
]
|
77
|
+
).build
|
78
|
+
end
|
79
|
+
|
80
|
+
subject(:valid_path_with_transformation) do
|
81
|
+
described_class.new(
|
82
|
+
[
|
83
|
+
{ field: :rating, from: [:ratings, :imdb], transformed: "Rating: %{value}" }
|
84
|
+
]
|
85
|
+
).build
|
86
|
+
end
|
87
|
+
|
88
|
+
subject(:valid_path_with_calculation) do
|
89
|
+
described_class.new(
|
90
|
+
[
|
91
|
+
{ field: :ratings, calculated: "IMDB: %{ratings.imdb}, Trakt: %{ratings.trakt}, Rotten Tommatoes: %{ratings.rotten_tomatoes}" }
|
92
|
+
]
|
93
|
+
).build
|
94
|
+
end
|
95
|
+
|
96
|
+
subject(:invalid_path) do
|
97
|
+
described_class.new(
|
98
|
+
[
|
99
|
+
{ field: :rating, from: [:very, :long, :path, :that, :might, :not, :exist] }
|
100
|
+
]
|
101
|
+
).build
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it_behaves_like "a morfer with nested destination" do
|
106
|
+
let(:definitions) do
|
107
|
+
[
|
108
|
+
{ field: [:tv_show, :title], from: :title },
|
109
|
+
{ field: [:tv_show, :channel], from: :channel, transformed: "Channel: %{value}" },
|
110
|
+
]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Morfo
|
4
|
+
module Tools
|
5
|
+
describe FlattenHashKeys do
|
6
|
+
subject { described_class.new(input_hash) }
|
7
|
+
|
8
|
+
context "symbol keys" do
|
9
|
+
context "flat hash" do
|
10
|
+
let(:input_hash) { { simple: :hash } }
|
11
|
+
let(:expected_output) { { simple: :hash } }
|
12
|
+
|
13
|
+
it "returns a new hash" do
|
14
|
+
expect(subject.flatten).not_to be(input_hash)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns the correct hash" do
|
18
|
+
expect(subject.flatten).to eq(expected_output)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "single nested hash" do
|
23
|
+
let(:input_hash) { { a: { nested: :hash } } }
|
24
|
+
let(:expected_output) { { :"a.nested" => :hash } }
|
25
|
+
|
26
|
+
it "returns a new hash" do
|
27
|
+
expect(subject.flatten).not_to be(input_hash)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns the correct hash" do
|
31
|
+
expect(subject.flatten).to eq(expected_output)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "multiple nested hash" do
|
36
|
+
let(:input_hash) { { a: { deeper: { nested: :hash } } } }
|
37
|
+
let(:expected_output) { { :"a.deeper.nested" => :hash } }
|
38
|
+
|
39
|
+
it "returns a new hash" do
|
40
|
+
expect(subject.flatten).not_to be(input_hash)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns the correct hash" do
|
44
|
+
expect(subject.flatten).to eq(expected_output)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "string keys" do
|
50
|
+
context "flat hash" do
|
51
|
+
let(:input_hash) { { "simple" => :hash } }
|
52
|
+
let(:expected_output) { { simple: :hash } }
|
53
|
+
|
54
|
+
it "returns a new hash" do
|
55
|
+
expect(subject.flatten).not_to be(input_hash)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns the correct hash" do
|
59
|
+
expect(subject.flatten).to eq(expected_output)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "single nested hash" do
|
64
|
+
let(:input_hash) { { "a" => { "nested" => :hash } } }
|
65
|
+
let(:expected_output) { { :"a.nested" => :hash } }
|
66
|
+
|
67
|
+
it "returns a new hash" do
|
68
|
+
expect(subject.flatten).not_to be(input_hash)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns the correct hash" do
|
72
|
+
expect(subject.flatten).to eq(expected_output)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "multiple nested hash" do
|
77
|
+
let(:input_hash) { { "a" => { "deeper" => { "nested" => :hash } } } }
|
78
|
+
let(:expected_output) { { :"a.deeper.nested" => :hash } }
|
79
|
+
|
80
|
+
it "returns a new hash" do
|
81
|
+
expect(subject.flatten).not_to be(input_hash)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "returns the correct hash" do
|
85
|
+
expect(subject.flatten).to eq(expected_output)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/spec/lib/morfo_spec.rb
CHANGED
@@ -1,287 +1,108 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe Morfo::Base do
|
4
|
-
|
5
|
-
[
|
6
|
-
{
|
7
|
-
title: 'The Walking Dead',
|
8
|
-
channel: 'AMC',
|
9
|
-
watchers: 1337,
|
10
|
-
status: 'running',
|
11
|
-
cast: ['Lincoln, Andrew', 'McBride, Melissa'],
|
12
|
-
ratings: {
|
13
|
-
imdb: 8.7,
|
14
|
-
trakt: 89,
|
15
|
-
rotten_tomatoes: 93,
|
16
|
-
},
|
17
|
-
},
|
18
|
-
{
|
19
|
-
title: 'Breaking Bad',
|
20
|
-
channel: 'AMC',
|
21
|
-
watchers: 72891,
|
22
|
-
status: 'ended',
|
23
|
-
cast: ['Cranston, Bryan', 'Gunn, Anna'],
|
24
|
-
ratings: {
|
25
|
-
imdb: 9.5,
|
26
|
-
trakt: 95,
|
27
|
-
rotten_tomatoes: 100,
|
28
|
-
},
|
29
|
-
}
|
30
|
-
]
|
31
|
-
end
|
32
|
-
|
33
|
-
let(:single_input) do
|
34
|
-
input.first
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'errors' do
|
4
|
+
it_behaves_like "an error throwing morfer" do
|
38
5
|
subject(:no_from) do
|
39
6
|
class NilMorfer < Morfo::Base
|
40
7
|
field(:my_field)
|
41
8
|
end
|
42
9
|
NilMorfer
|
43
10
|
end
|
44
|
-
|
45
|
-
describe '#morf' do
|
46
|
-
it 'raises error for nil field' do
|
47
|
-
expect{no_from.morf([{my_field: :something}])}.to raise_error(ArgumentError)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
describe '#morf_single' do
|
52
|
-
it 'raises error for nil field' do
|
53
|
-
expect{no_from.morf_single({my_field: :something})}.to raise_error(ArgumentError)
|
54
|
-
end
|
55
|
-
end
|
56
11
|
end
|
57
12
|
|
58
|
-
|
13
|
+
it_behaves_like "a 1 to 1 morfer" do
|
59
14
|
subject do
|
60
15
|
class TitleMorfer < Morfo::Base
|
61
16
|
field(:tv_show_title).from(:title)
|
62
17
|
end
|
63
18
|
TitleMorfer
|
64
19
|
end
|
65
|
-
|
66
|
-
describe '#morf' do
|
67
|
-
it 'maps title correctly' do
|
68
|
-
expected_output = input.map{|v| {tv_show_title: v[:title]} }
|
69
|
-
expect(subject.morf(input)).to eq(expected_output)
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'leaves out nil values in result' do
|
73
|
-
expected_output = [{},{}]
|
74
|
-
modified_input = input.map{|h| h.reject{|k, v| k == :title}}
|
75
|
-
expect(subject.morf(modified_input)).to eq(expected_output)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe '#morf_single' do
|
80
|
-
it 'maps title correctly' do
|
81
|
-
expected_output = { tv_show_title: single_input[:title] }
|
82
|
-
expect(subject.morf_single(single_input)).to eq(expected_output)
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'leaves out nil values in result' do
|
86
|
-
expected_output = {}
|
87
|
-
modified_input = single_input.reject { |k, v| k == :title }
|
88
|
-
expect(subject.morf_single(modified_input)).to eq(expected_output)
|
89
|
-
end
|
90
|
-
end
|
91
20
|
end
|
92
21
|
|
93
|
-
|
22
|
+
it_behaves_like "a 1 to 1 morfer with transformation" do
|
94
23
|
subject do
|
95
|
-
class
|
96
|
-
field(:
|
97
|
-
end
|
98
|
-
NumCastMorfer
|
99
|
-
end
|
100
|
-
|
101
|
-
describe '#morf' do
|
102
|
-
it 'calls transformation correctly' do
|
103
|
-
expected_output = input.map{|v| {cast_num: v[:cast].size} }
|
104
|
-
expect(subject.morf(input)).to eq(expected_output)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
describe '#morf_single' do
|
109
|
-
it 'calls transformation correctly' do
|
110
|
-
expected_output = { cast_num: single_input[:cast].size }
|
111
|
-
expect(subject.morf_single(single_input)).to eq(expected_output)
|
24
|
+
class AndZombies < Morfo::Base
|
25
|
+
field(:title).from(:title).transformed{|v| "#{v} and Zombies"}
|
112
26
|
end
|
27
|
+
AndZombies
|
113
28
|
end
|
114
29
|
end
|
115
30
|
|
116
|
-
|
31
|
+
it_behaves_like "a 1 to many morfer" do
|
117
32
|
subject do
|
118
|
-
class
|
33
|
+
class MultiTitleMorfer < Morfo::Base
|
119
34
|
field(:title).from(:title)
|
120
35
|
field(:also_title).from(:title)
|
121
36
|
end
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
describe '#morf' do
|
126
|
-
it 'maps title to multiple fields' do
|
127
|
-
expected_output = input.map{|v| {title: v[:title], also_title: v[:title]} }
|
128
|
-
expect(subject.morf(input)).to eq(expected_output)
|
129
|
-
end
|
37
|
+
MultiTitleMorfer
|
130
38
|
end
|
39
|
+
end
|
131
40
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
41
|
+
it_behaves_like "a calculating morfer" do
|
42
|
+
subject do
|
43
|
+
class TitlePrefixMorfer < Morfo::Base
|
44
|
+
field(:title_with_channel).calculated{|r| "#{r[:title]}, (#{r[:channel]})"}
|
136
45
|
end
|
46
|
+
TitlePrefixMorfer
|
137
47
|
end
|
138
48
|
end
|
139
49
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
field(:rating).from(:ratings, :imdb)
|
145
|
-
end
|
146
|
-
ImdbRatingMorfer
|
147
|
-
end
|
148
|
-
|
149
|
-
subject(:valid_path_with_transformation) do
|
150
|
-
class ImdbRatingMorferWithTransformation < Morfo::Base
|
151
|
-
field(:rating).from(:ratings, :imdb).transformed {|v| "Rating: #{v}"}
|
152
|
-
end
|
153
|
-
ImdbRatingMorferWithTransformation
|
154
|
-
end
|
155
|
-
|
156
|
-
subject(:invalid_path) do
|
157
|
-
class InvalidImdbRatingMorfer < Morfo::Base
|
158
|
-
field(:rating).from(:very, :long, :path, :that, :might, :not, :exist)
|
159
|
-
end
|
160
|
-
InvalidImdbRatingMorfer
|
161
|
-
end
|
162
|
-
|
163
|
-
describe '#morf' do
|
164
|
-
it 'maps nested attributes' do
|
165
|
-
expected_output = input.map{|v| {rating: v[:ratings][:imdb]} }
|
166
|
-
expect(valid_path.morf(input)).to eq(expected_output)
|
167
|
-
end
|
168
|
-
|
169
|
-
it 'maps nested attributes with transformation' do
|
170
|
-
expected_output = input.map{|v| {rating: "Rating: #{v[:ratings][:imdb]}"} }
|
171
|
-
expect(valid_path_with_transformation.morf(input)).to eq(expected_output)
|
172
|
-
end
|
173
|
-
|
174
|
-
it 'doesn\'t raise error for invalid path' do
|
175
|
-
expected_output = [{},{}]
|
176
|
-
expect(invalid_path.morf(input)).to eq(expected_output)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
describe '#morf_single' do
|
181
|
-
it 'maps nested attributes' do
|
182
|
-
expected_output = {rating: single_input[:ratings][:imdb]}
|
183
|
-
expect(valid_path.morf_single(single_input)).to eq(expected_output)
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'maps nested attributes with transformation' do
|
187
|
-
expected_output = {rating: "Rating: #{single_input[:ratings][:imdb]}"}
|
188
|
-
expect(valid_path_with_transformation.morf_single(single_input)).to eq(expected_output)
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'doesn\'t raise error for invalid path' do
|
192
|
-
expected_output = { }
|
193
|
-
expect(invalid_path.morf_single(single_input)).to eq(expected_output)
|
194
|
-
end
|
50
|
+
it_behaves_like "a static morfer" do
|
51
|
+
subject do
|
52
|
+
class StaticTitleMorfer < Morfo::Base
|
53
|
+
field(:new_title).calculated{ "Static Title" }
|
195
54
|
end
|
55
|
+
StaticTitleMorfer
|
196
56
|
end
|
57
|
+
end
|
197
58
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
field(:tv_show, :channel).from(:channel).transformed {|v| "Channel: #{v}"}
|
203
|
-
end
|
204
|
-
WrapperMorfer
|
205
|
-
end
|
206
|
-
|
207
|
-
describe '#morf' do
|
208
|
-
it 'maps to nested destination' do
|
209
|
-
expected_output = input.map{|v|
|
210
|
-
{
|
211
|
-
tv_show: {
|
212
|
-
title: v[:title],
|
213
|
-
channel: "Channel: #{v[:channel]}",
|
214
|
-
}
|
215
|
-
}
|
216
|
-
}
|
217
|
-
expect(subject.morf(input)).to eq(expected_output)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
describe '#morf_single' do
|
222
|
-
it 'maps to nested destination' do
|
223
|
-
expected_output = {
|
224
|
-
tv_show: {
|
225
|
-
title: single_input[:title],
|
226
|
-
channel: "Channel: #{single_input[:channel]}",
|
227
|
-
}
|
228
|
-
}
|
229
|
-
expect(subject.morf_single(single_input)).to eq(expected_output)
|
230
|
-
end
|
59
|
+
it_behaves_like "a morfer with nested source" do
|
60
|
+
subject(:valid_path) do
|
61
|
+
class ImdbRatingMorfer < Morfo::Base
|
62
|
+
field(:rating).from(:ratings, :imdb)
|
231
63
|
end
|
64
|
+
ImdbRatingMorfer
|
232
65
|
end
|
233
|
-
end
|
234
66
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
field(:title_with_channel).calculated{|r| "#{r[:title]}, (#{r[:channel]})"}
|
67
|
+
subject(:valid_path_with_transformation) do
|
68
|
+
class ImdbRatingMorferWithTransformation < Morfo::Base
|
69
|
+
field(:rating).from(:ratings, :imdb).transformed {|v| "Rating: #{v}"}
|
239
70
|
end
|
240
|
-
|
71
|
+
ImdbRatingMorferWithTransformation
|
241
72
|
end
|
242
73
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
{
|
247
|
-
title_with_channel: "#{r[:title]}, (#{r[:channel]})"
|
248
|
-
}
|
249
|
-
}
|
250
|
-
expect(subject.morf(input)).to eq(expected_output)
|
74
|
+
subject(:valid_path_with_calculation) do
|
75
|
+
class ImdbRatingMorferWithCalculation < Morfo::Base
|
76
|
+
field(:ratings).calculated {|r| "IMDB: #{r[:ratings][:imdb]}, Trakt: #{r[:ratings][:trakt]}, Rotten Tommatoes: #{r[:ratings][:rotten_tomatoes]}" }
|
251
77
|
end
|
78
|
+
ImdbRatingMorferWithCalculation
|
252
79
|
end
|
253
80
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
title_with_channel: "#{single_input[:title]}, (#{single_input[:channel]})"
|
258
|
-
}
|
259
|
-
|
260
|
-
expect(subject.morf_single(single_input)).to eq(expected_output)
|
81
|
+
subject(:invalid_path) do
|
82
|
+
class InvalidImdbRatingMorfer < Morfo::Base
|
83
|
+
field(:rating).from(:very, :long, :path, :that, :might, :not, :exist)
|
261
84
|
end
|
85
|
+
InvalidImdbRatingMorfer
|
262
86
|
end
|
263
87
|
end
|
264
88
|
|
265
|
-
|
89
|
+
it_behaves_like "a morfer with nested destination" do
|
266
90
|
subject do
|
267
|
-
class
|
268
|
-
field(:
|
269
|
-
|
270
|
-
StaticTitleMorfer
|
271
|
-
end
|
272
|
-
|
273
|
-
describe '#morf' do
|
274
|
-
it 'maps static value correctly' do
|
275
|
-
expected_output = input.map{|r| {new_title: 'Static Title'} }
|
276
|
-
expect(subject.morf(input)).to eq(expected_output)
|
91
|
+
class WrapperMorfer < Morfo::Base
|
92
|
+
field(:tv_show, :title).from(:title)
|
93
|
+
field(:tv_show, :channel).from(:channel).transformed {|v| "Channel: #{v}"}
|
277
94
|
end
|
95
|
+
WrapperMorfer
|
278
96
|
end
|
97
|
+
end
|
279
98
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
99
|
+
it_behaves_like "a morfer with nested destination" do
|
100
|
+
subject do
|
101
|
+
class WrapperMorfer < Morfo::Base
|
102
|
+
field(:tv_show, :title).from(:title)
|
103
|
+
field(:tv_show, :channel).from(:channel).transformed {|v| "Channel: #{v}"}
|
284
104
|
end
|
105
|
+
WrapperMorfer
|
285
106
|
end
|
286
107
|
end
|
287
108
|
end
|