morfo 0.0.3 → 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/README.md +37 -56
- data/benchmarks/data.rb +74 -0
- data/benchmarks/run.rb +46 -0
- data/lib/morfo/actions/base.rb +0 -0
- data/lib/morfo/actions.rb +56 -0
- data/lib/morfo/version.rb +1 -1
- data/lib/morfo.rb +11 -41
- data/spec/lib/morfo_spec.rb +77 -23
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7bb20ae90a7b011588d8e096694b69fab5664684
|
4
|
+
data.tar.gz: 00b3eb367ac96a797105118974ca2562a35d4163
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c84f9323b71740ee3056033a25974a7daefedd3e29e92b40138bf5591e1b3a186349527d4cf13865c8a91bcbd260f01587857917dae74eca157351250de3f321
|
7
|
+
data.tar.gz: d052cce267ede1514bb6bb70c2db3eabbc3c4f01273d337c95b399986a683f0516ea2175fc43b0ad6fbf9003a1789fc62054ac498d6cc5747a886c564985db9e
|
data/README.md
CHANGED
@@ -2,9 +2,7 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/leifg/morfo.png?branch=master)](https://travis-ci.org/leifg/morfo) [![Coverage Status](https://coveralls.io/repos/leifg/morfo/badge.png?branch=master)](https://coveralls.io/r/leifg/morfo) [![Code Climate](https://codeclimate.com/github/leifg/morfo.png)](https://codeclimate.com/github/leifg/morfo) [![Dependency Status](https://gemnasium.com/leifg/morfo.png)](https://gemnasium.com/leifg/morfo) [![Gem Version](https://badge.fury.io/rb/morfo.png)](http://badge.fury.io/rb/morfo)
|
4
4
|
|
5
|
-
This
|
6
|
-
|
7
|
-
But instead of importing spreadsheets into models, you can morf (typo intended) arrays of Hashes into other arrays of hashes.
|
5
|
+
This gem acts like a universal converter from hashes into other hashes. You just define where your hash should get its data from and morfo will do the rest for you.
|
8
6
|
|
9
7
|
## Compatibility
|
10
8
|
|
@@ -28,10 +26,14 @@ Or install it yourself as:
|
|
28
26
|
|
29
27
|
In order to morf the hashes you have to provide a class that extends `Morf::Base`
|
30
28
|
|
31
|
-
Use the `
|
29
|
+
Use the `field` method to specify what fields exist and where they will get their data from:
|
30
|
+
|
31
|
+
### Simple Mapping
|
32
|
+
|
33
|
+
The most basic form is, just define another field from the input hash. The value will just be copied.
|
32
34
|
|
33
35
|
class Title < Morfo::Base
|
34
|
-
|
36
|
+
field :tv_show_title, from: :title
|
35
37
|
end
|
36
38
|
|
37
39
|
Afterwards use the `morf` method to morf all hashes in one array to the end result:
|
@@ -46,50 +48,12 @@ Afterwards use the `morf` method to morf all hashes in one array to the end resu
|
|
46
48
|
# {tv_show_title: 'Breaking Bad'},
|
47
49
|
# ]
|
48
50
|
|
49
|
-
|
50
|
-
|
51
|
-
class MultiTitle < Morfo::Base
|
52
|
-
map :title, :tv_show_title
|
53
|
-
map :title, :show_title
|
54
|
-
end
|
55
|
-
|
56
|
-
MultiTitle.morf([
|
57
|
-
{title: 'The Walking Dead'} ,
|
58
|
-
{title: 'Breaking Bad'},
|
59
|
-
])
|
60
|
-
|
61
|
-
# [
|
62
|
-
# {tv_show_title: 'The Walking Dead', show_title: 'The Walking Dead'},
|
63
|
-
# {tv_show_title: 'Breaking Bad', show_title: 'Breaking Bad'},
|
64
|
-
# ]
|
65
|
-
|
66
|
-
## Transformations
|
67
|
-
|
68
|
-
For each mapping you can define a block, that will be called on every input:
|
69
|
-
|
70
|
-
class AndZombies < Morfo::Base
|
71
|
-
map :title, :title do |title|
|
72
|
-
"#{title} and Zombies"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
AndZombies.morf([
|
77
|
-
{title: 'Pride and Prejudice'},
|
78
|
-
{title: 'Fifty Shades of Grey'},
|
79
|
-
])
|
80
|
-
|
81
|
-
# [
|
82
|
-
# {title: 'Pride and Prejudice and Zombies'},
|
83
|
-
# {title: 'Fifty Shades of Grey and Zombies'},
|
84
|
-
# ]
|
85
|
-
|
86
|
-
## Nested Values
|
51
|
+
If you want to have access to nested values, you'll have to provide an array as the key:
|
87
52
|
|
88
|
-
You can directly access nested values in the hashes:
|
89
53
|
|
90
54
|
class Name < Morfo::Base
|
91
|
-
|
92
|
-
|
55
|
+
field :first_name, from: [:name, :first]
|
56
|
+
field :last_name, from: [:name, :last]
|
93
57
|
end
|
94
58
|
|
95
59
|
Name.morf([
|
@@ -112,22 +76,39 @@ You can directly access nested values in the hashes:
|
|
112
76
|
# {first_name: 'Bruce',last_name: 'Wayne'},
|
113
77
|
# ]
|
114
78
|
|
79
|
+
## Transformations
|
115
80
|
|
116
|
-
|
81
|
+
Every field can also take a transformation block, so that the original input can be transformed.
|
117
82
|
|
118
|
-
class
|
119
|
-
|
120
|
-
map :last_name, [:superhero, :name, :last]
|
83
|
+
class AndZombies < Morfo::Base
|
84
|
+
field(:title, from: :title) {|title| "#{title} and Zombies"}
|
121
85
|
end
|
122
86
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
87
|
+
AndZombies.morf([
|
88
|
+
{title: 'Pride and Prejudice'},
|
89
|
+
{title: 'Fifty Shades of Grey'},
|
90
|
+
])
|
91
|
+
|
92
|
+
# [
|
93
|
+
# {title: 'Pride and Prejudice and Zombies'},
|
94
|
+
# {title: 'Fifty Shades of Grey and Zombies'},
|
95
|
+
# ]
|
96
|
+
|
97
|
+
As the second argument, the whole row is passed into the block. So you can even do transformation based on the whole row. Or you can leave out all the arguments and return a static value.
|
98
|
+
|
99
|
+
class NameConcatenator < Morfo::Base
|
100
|
+
field(:name) {|_, row| "#{row[:first_name]} #{row[:last_name]}"}
|
101
|
+
field(:status) { 'Best Friend' }
|
102
|
+
end
|
103
|
+
|
104
|
+
NameConcatenator.morf([
|
105
|
+
{first_name: 'Robin', last_name: 'Hood'},
|
106
|
+
{first_name: 'Sherlock', last_name: 'Holmes'},
|
107
|
+
])
|
127
108
|
|
128
109
|
# [
|
129
|
-
# {
|
130
|
-
# {
|
110
|
+
# {:name=>"Robin Hood", :status=>"Best Friend"},
|
111
|
+
# {:name=>"Sherlock Holmes", :status=>'Best Friend'}
|
131
112
|
# ]
|
132
113
|
|
133
114
|
|
data/benchmarks/data.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module BenchmarkData
|
2
|
+
extend self
|
3
|
+
|
4
|
+
def nested_wrapper
|
5
|
+
:person
|
6
|
+
end
|
7
|
+
|
8
|
+
def row
|
9
|
+
{
|
10
|
+
first_name: 'Jazmyn',
|
11
|
+
last_name: 'Willms',
|
12
|
+
gender: 'female',
|
13
|
+
phone_number: '485-675-9228',
|
14
|
+
cell_phone: '1-172-435-9402 x4907',
|
15
|
+
street_name: 'Becker Inlet',
|
16
|
+
street_number: '15a',
|
17
|
+
city: 'Carolynchester',
|
18
|
+
zip: '38189',
|
19
|
+
country: 'USA',
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def row_string_keys
|
24
|
+
stringify_keys(row)
|
25
|
+
end
|
26
|
+
|
27
|
+
def row_nested
|
28
|
+
{
|
29
|
+
nested_wrapper => row
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def row_nested_string_keys
|
34
|
+
{
|
35
|
+
nested_wrapper.to_s => row_string_keys
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def stringify_keys hash
|
41
|
+
hash.keys.each do |key|
|
42
|
+
hash[key.to_s] = hash.delete(key)
|
43
|
+
end
|
44
|
+
hash
|
45
|
+
end
|
46
|
+
|
47
|
+
class SimpleMorferSymbol < Morfo::Base
|
48
|
+
BenchmarkData.row.keys.each do |field|
|
49
|
+
field(:"#{field}_mapped", from: field)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class SimpleMorferString < Morfo::Base
|
54
|
+
BenchmarkData.row_string_keys.keys.each do |field|
|
55
|
+
field("#{field}_mapped", from: field)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class NestedMorferSymbol < Morfo::Base
|
60
|
+
BenchmarkData.row_nested.each do |key, value|
|
61
|
+
value.keys.each do |field|
|
62
|
+
field(:"#{field}_mapped", from: [key, field])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class NestedMorferString < Morfo::Base
|
68
|
+
BenchmarkData.row_nested_string_keys.each do |key, value|
|
69
|
+
value.keys.each do |field|
|
70
|
+
field("#{field}_mapped", from: [key, field])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/benchmarks/run.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'morfo'
|
2
|
+
require 'benchmark'
|
3
|
+
require './benchmarks/data'
|
4
|
+
|
5
|
+
iterations = 100
|
6
|
+
batch_size = 10000
|
7
|
+
|
8
|
+
definitions = [
|
9
|
+
{
|
10
|
+
label: 'Simple (strings)',
|
11
|
+
row: BenchmarkData.row_string_keys,
|
12
|
+
morf_class: BenchmarkData::SimpleMorferString
|
13
|
+
},
|
14
|
+
{
|
15
|
+
label: 'Simple (symbols)',
|
16
|
+
row: BenchmarkData.row,
|
17
|
+
morf_class: BenchmarkData::SimpleMorferSymbol
|
18
|
+
},
|
19
|
+
{
|
20
|
+
label: 'Nested (strings)',
|
21
|
+
row: BenchmarkData.row_nested_string_keys,
|
22
|
+
morf_class: BenchmarkData::NestedMorferString
|
23
|
+
},
|
24
|
+
{
|
25
|
+
label: 'Nested (symbols)',
|
26
|
+
row: BenchmarkData.row_nested,
|
27
|
+
morf_class: BenchmarkData::NestedMorferSymbol
|
28
|
+
},
|
29
|
+
]
|
30
|
+
|
31
|
+
definitions.each do |defintition|
|
32
|
+
defintition.merge!(
|
33
|
+
data: Array.new(batch_size){ defintition[:row] }
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
Benchmark.bm(20) do |x|
|
38
|
+
definitions.each do |defintition|
|
39
|
+
x.report(defintition[:label]) do
|
40
|
+
iterations.times do
|
41
|
+
defintition[:morf_class].morf(defintition[:data])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
File without changes
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Morfo
|
2
|
+
module Actions
|
3
|
+
module ValueMethods
|
4
|
+
def extract_value from, row
|
5
|
+
Array(from).inject(row) do |resulting_value, key|
|
6
|
+
resulting_value ? resulting_value[key] : nil
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def store_value to, value
|
11
|
+
return {} if value.nil?
|
12
|
+
|
13
|
+
Array(to).reverse.inject({}) do |hash, key|
|
14
|
+
if hash.keys.first.nil?
|
15
|
+
hash.merge!(key => value)
|
16
|
+
else
|
17
|
+
{ key => hash }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class MapAction
|
24
|
+
include ValueMethods
|
25
|
+
attr_reader :from
|
26
|
+
attr_reader :to
|
27
|
+
|
28
|
+
def initialize from, to
|
29
|
+
@from = from
|
30
|
+
@to = to
|
31
|
+
end
|
32
|
+
|
33
|
+
def execute row
|
34
|
+
store_value(to, extract_value(from, row))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class TransformationAction
|
39
|
+
include ValueMethods
|
40
|
+
attr_reader :to
|
41
|
+
attr_reader :from
|
42
|
+
attr_reader :transformation
|
43
|
+
|
44
|
+
def initialize from, to, transformation
|
45
|
+
@from = from
|
46
|
+
@to = to
|
47
|
+
@transformation = transformation
|
48
|
+
end
|
49
|
+
|
50
|
+
def execute row
|
51
|
+
resulting_value = from ? extract_value(from, row) : nil
|
52
|
+
store_value(to, transformation.call(resulting_value,row))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/morfo/version.rb
CHANGED
data/lib/morfo.rb
CHANGED
@@ -1,9 +1,18 @@
|
|
1
1
|
require 'morfo/version'
|
2
|
+
require 'morfo/actions'
|
2
3
|
|
3
4
|
module Morfo
|
4
5
|
class Base
|
5
|
-
def self.
|
6
|
-
|
6
|
+
def self.field field_name, definition={}, &blk
|
7
|
+
if blk
|
8
|
+
mapping_actions << Morfo::Actions::TransformationAction.new(definition[:from], field_name, blk)
|
9
|
+
else
|
10
|
+
raise(
|
11
|
+
ArgumentError,
|
12
|
+
"No field to get value from is specified for #{field_name.inspect}"
|
13
|
+
) unless definition[:from]
|
14
|
+
mapping_actions << Morfo::Actions::MapAction.new(definition[:from], field_name)
|
15
|
+
end
|
7
16
|
end
|
8
17
|
|
9
18
|
def self.morf input
|
@@ -31,43 +40,4 @@ module Morfo
|
|
31
40
|
hash
|
32
41
|
end
|
33
42
|
end
|
34
|
-
|
35
|
-
class MapAction
|
36
|
-
attr_reader :from
|
37
|
-
attr_reader :to
|
38
|
-
attr_reader :transformation
|
39
|
-
|
40
|
-
def initialize from, to, transformation
|
41
|
-
@from = from
|
42
|
-
@to = to
|
43
|
-
@transformation = transformation
|
44
|
-
end
|
45
|
-
|
46
|
-
def execute row
|
47
|
-
resulting_value = apply_transformation(extract_value(row))
|
48
|
-
resulting_value ? store_value(to, resulting_value) : {}
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
def extract_value row
|
53
|
-
Array(from).inject(row) do |resulting_value, key|
|
54
|
-
resulting_value ? resulting_value[key] : nil
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def apply_transformation row
|
59
|
-
transformation ? transformation.call(row) : row
|
60
|
-
end
|
61
|
-
|
62
|
-
def store_value to, value
|
63
|
-
Array(to).reverse.inject({}) do |hash, key|
|
64
|
-
if hash.keys.first.nil?
|
65
|
-
hash.merge!(key => value)
|
66
|
-
else
|
67
|
-
{ key => hash }
|
68
|
-
end
|
69
|
-
end
|
70
|
-
#{ to => value }
|
71
|
-
end
|
72
|
-
end
|
73
43
|
end
|
data/spec/lib/morfo_spec.rb
CHANGED
@@ -31,12 +31,24 @@ describe Morfo::Base do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
describe '#morf' do
|
34
|
+
context 'errors' do
|
35
|
+
subject(:no_from) do
|
36
|
+
class NilMorfer < Morfo::Base
|
37
|
+
field :my_field, {}
|
38
|
+
end
|
39
|
+
NilMorfer
|
40
|
+
end
|
41
|
+
it 'raises error for nil field' do
|
42
|
+
expect{no_from.morf([])}.to raise_error(ArgumentError)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
34
46
|
context '1 to 1 conversion' do
|
35
47
|
subject do
|
36
|
-
class
|
37
|
-
|
48
|
+
class TitleMorfer < Morfo::Base
|
49
|
+
field :tv_show_title, from: :title
|
38
50
|
end
|
39
|
-
|
51
|
+
TitleMorfer
|
40
52
|
end
|
41
53
|
|
42
54
|
it 'maps title correctly' do
|
@@ -53,12 +65,10 @@ describe Morfo::Base do
|
|
53
65
|
|
54
66
|
context '1 to 1 conversion with transformation' do
|
55
67
|
subject do
|
56
|
-
class
|
57
|
-
|
58
|
-
cast.size
|
59
|
-
end
|
68
|
+
class NumCastMorfer < Morfo::Base
|
69
|
+
field(:cast_num, from: :cast){|v,r| v.size}
|
60
70
|
end
|
61
|
-
|
71
|
+
NumCastMorfer
|
62
72
|
end
|
63
73
|
|
64
74
|
it 'calls transformation correctly' do
|
@@ -69,11 +79,11 @@ describe Morfo::Base do
|
|
69
79
|
|
70
80
|
context '1 to many conversion' do
|
71
81
|
subject do
|
72
|
-
class
|
73
|
-
|
74
|
-
|
82
|
+
class MutliTitleMorfer < Morfo::Base
|
83
|
+
field :title, from: :title
|
84
|
+
field :also_title, from: :title
|
75
85
|
end
|
76
|
-
|
86
|
+
MutliTitleMorfer
|
77
87
|
end
|
78
88
|
|
79
89
|
it 'maps title to multiple fields' do
|
@@ -85,17 +95,24 @@ describe Morfo::Base do
|
|
85
95
|
context 'nested conversion' do
|
86
96
|
context 'nested source' do
|
87
97
|
subject(:valid_path) do
|
88
|
-
class
|
89
|
-
|
98
|
+
class ImdbRatingMorfer < Morfo::Base
|
99
|
+
field :rating, from: [:ratings, :imdb]
|
100
|
+
end
|
101
|
+
ImdbRatingMorfer
|
102
|
+
end
|
103
|
+
|
104
|
+
subject(:valid_path_with_transformation) do
|
105
|
+
class ImdbRatingMorfer < Morfo::Base
|
106
|
+
field(:rating, from: [:ratings, :imdb]){|v| "Rating: #{v}"}
|
90
107
|
end
|
91
|
-
|
108
|
+
ImdbRatingMorfer
|
92
109
|
end
|
93
110
|
|
94
111
|
subject(:invalid_path) do
|
95
|
-
class
|
96
|
-
|
112
|
+
class InvalidImdbRatingMorfer < Morfo::Base
|
113
|
+
field :rating, from: [:very, :long, :path, :that, :might, :not, :exist]
|
97
114
|
end
|
98
|
-
|
115
|
+
InvalidImdbRatingMorfer
|
99
116
|
end
|
100
117
|
|
101
118
|
it 'maps nested attributes' do
|
@@ -103,6 +120,11 @@ describe Morfo::Base do
|
|
103
120
|
expect(valid_path.morf(input)).to eq(expected_output)
|
104
121
|
end
|
105
122
|
|
123
|
+
it 'maps nested attributes with transformation' do
|
124
|
+
expected_output = input.map{|v| {rating: "Rating: #{v[:ratings][:imdb]}"} }
|
125
|
+
expect(valid_path_with_transformation.morf(input)).to eq(expected_output)
|
126
|
+
end
|
127
|
+
|
106
128
|
it 'doesn\'t raise error for invalid path' do
|
107
129
|
expected_output = [{},{}]
|
108
130
|
expect(invalid_path.morf(input)).to eq(expected_output)
|
@@ -111,11 +133,11 @@ describe Morfo::Base do
|
|
111
133
|
|
112
134
|
context 'nested destination' do
|
113
135
|
subject do
|
114
|
-
class
|
115
|
-
|
116
|
-
|
136
|
+
class WrapperMorfer < Morfo::Base
|
137
|
+
field([:tv_show, :title], from: :title)
|
138
|
+
field([:tv_show, :channel], from: :channel){|v| "Channel: #{v}"}
|
117
139
|
end
|
118
|
-
|
140
|
+
WrapperMorfer
|
119
141
|
end
|
120
142
|
|
121
143
|
it 'maps to nested destination' do
|
@@ -123,7 +145,7 @@ describe Morfo::Base do
|
|
123
145
|
{
|
124
146
|
tv_show: {
|
125
147
|
title: v[:title],
|
126
|
-
channel: v[:channel],
|
148
|
+
channel: "Channel: #{v[:channel]}",
|
127
149
|
}
|
128
150
|
}
|
129
151
|
}
|
@@ -131,5 +153,37 @@ describe Morfo::Base do
|
|
131
153
|
end
|
132
154
|
end
|
133
155
|
end
|
156
|
+
|
157
|
+
context 'calculations' do
|
158
|
+
subject do
|
159
|
+
class TitlePrefixMorfer < Morfo::Base
|
160
|
+
field(:title_with_channel){|v,r| "#{r[:title]}, (#{r[:channel]})"}
|
161
|
+
end
|
162
|
+
TitlePrefixMorfer
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'maps calculation correctly' do
|
166
|
+
expected_output = input.map{|r|
|
167
|
+
{
|
168
|
+
title_with_channel: "#{r[:title]}, (#{r[:channel]})"
|
169
|
+
}
|
170
|
+
}
|
171
|
+
expect(subject.morf(input)).to eq(expected_output)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context 'static values' do
|
176
|
+
subject do
|
177
|
+
class StaticTitleMorfer < Morfo::Base
|
178
|
+
field(:new_title){ 'Static Title' }
|
179
|
+
end
|
180
|
+
StaticTitleMorfer
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'maps static value correctly' do
|
184
|
+
expected_output = input.map{|r| {new_title: 'Static Title'} }
|
185
|
+
expect(subject.morf(input)).to eq(expected_output)
|
186
|
+
end
|
187
|
+
end
|
134
188
|
end
|
135
189
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morfo
|
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
|
- Leif Gensert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -73,7 +73,11 @@ files:
|
|
73
73
|
- LICENSE.txt
|
74
74
|
- README.md
|
75
75
|
- Rakefile
|
76
|
+
- benchmarks/data.rb
|
77
|
+
- benchmarks/run.rb
|
76
78
|
- lib/morfo.rb
|
79
|
+
- lib/morfo/actions.rb
|
80
|
+
- lib/morfo/actions/base.rb
|
77
81
|
- lib/morfo/version.rb
|
78
82
|
- morfo.gemspec
|
79
83
|
- spec/lib/morfo_spec.rb
|