yahm 0.1.0 → 0.2.0

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: 2f91884e21f0dc68a1777f51cda708d53f053608
4
- data.tar.gz: c3ad59e14872e528f9a19d3b203645dbc9f9d36e
3
+ metadata.gz: 9fe26e652bc9220089279697888c2caa5b3469b4
4
+ data.tar.gz: 49fcff2c3a44c6e2fcd3a870eb3db4521bdc47be
5
5
  SHA512:
6
- metadata.gz: 9d57cb78535fd2ef77a611088ed6311d0932b406e27b366de9f9ddc7477837ca14c7bbfb3814f3ce7f36a430e808186fb088528addbc979e151bcd6e0c0933ae
7
- data.tar.gz: a59e91fd750bd9640cee0e3d71bb989fa7a6b8fafdf0748f927f725373344ff7e03649b18e92d5133edac055992c379bc314d592b890d8b8dddaba9cc1afce54
6
+ metadata.gz: 20b69251b456cb660f337f03eb9e18357a8f6d3f3d8a20db461b49021dd1566a0ddaa33828efbc9750448f58a4508459a8f25815d9c6387995b2554076882021
7
+ data.tar.gz: 0062463e2cf0ac9bbea45c04deb07cffe4302eb83cb059d2126a8e618b601aee08ddaf135594884a2b11230b3b91d7633be23fbef05cad819f2e443914f265b9
data/README.md CHANGED
@@ -69,7 +69,21 @@ end
69
69
  Record.new({ ... })
70
70
  => { :id => "...", :count => ..., :subjects => { :most_important_subject => "..."}, ... }
71
71
  ```
72
- ### Options
72
+ ### Mapping options
73
+
74
+ #### `context:`
75
+
76
+ Something that responds to a method call, e.g. a class. Is used the resolve undefined methods of lambdas/procs.
77
+
78
+ #### `use_threads: [true|false]` [experimental]
79
+
80
+ Use a thread pool to execute to rules of a mapping. The current implementation is very naiv. No locking of shared data etc. Use this *only* if *you know* what you are doing and if your rules a complex enough to compensate the overhead introduced by threading.
81
+
82
+ #### `thread_pool_size: [number]` [experimental]
83
+
84
+ The number of threads used to execute rules if `use_threads: true`.
85
+
86
+ ### Per rule options
73
87
 
74
88
  #### `to: [string|lambda|proc]`
75
89
 
@@ -91,14 +105,6 @@ You can pass a lambda/proc as `processed_by` option. Inside of lambdas or procs,
91
105
 
92
106
  If a value is a string and `split_by` is supplied, the string is splitted by the given character and an array would be returned.
93
107
 
94
- #### `use_threads: [true|false]` [experimental]
95
-
96
- Use a thread pool to execute to rules of a mapping. The current implementation is very naiv. No locking of shared data etc. Use this *only* if *you know* what you are doing and if your rules a complex enough to compensate the overhead introduced by threading.
97
-
98
- #### `thread_pool_size: [number]` [experimental]
99
-
100
- The number of threads used to execute rules if `use_threads: true`.
101
-
102
108
  ## Related work
103
109
 
104
110
  * hash_mapper (https://github.com/ismasan/hash_mapper)
@@ -1,137 +1,6 @@
1
- require "yahm/version"
1
+ require "hpath"
2
2
 
3
3
  class Yahm
4
4
  require "yahm/mapping"
5
-
6
- def self.get(object, path)
7
- current_path_element, remaining_path = split_path(path)
8
-
9
- if hash_path?(current_path_element) && object.is_a?(Hash)
10
- key = current_path_element[1..-1]
11
-
12
- # handle cases where one forces symbol/string keys
13
- value =
14
- if key.start_with?(":")
15
- object[key[1..-1].to_sym]
16
- elsif key.start_with?('"') && key.end_with?('"')
17
- object[key[1..-2]]
18
- else
19
- object[key.to_sym] || object[key.to_s]
20
- end
21
-
22
- unless value.nil?
23
- remaining_path ? self.get(value, remaining_path) : value
24
- else
25
- value
26
- end
27
- elsif array_path?(current_path_element) && object.is_a?(Array)
28
- index_parameter = current_path_element.slice(1..-2)
29
-
30
- index =
31
- if index_parameter == ""
32
- 0..object.length
33
- else
34
- index_parameter.to_i
35
- end
36
-
37
- if remaining_path
38
- unless object[index].nil?
39
- map_result = object[index.is_a?(Range) ? index : index..index].map do |array_element|
40
- self.get(array_element, remaining_path)
41
- end.compact
42
-
43
- map_result == [] ? nil : map_result.flatten(array_depth(map_result) - 1)
44
- else
45
- nil
46
- end
47
- else
48
- object[index]
49
- end
50
- end
51
- end
52
-
53
- def self.set(object, path, value)
54
- current_path_element, remaining_path = split_path(path)
55
- next_path_element = split_path(remaining_path)[0]
56
-
57
- if hash_path?(current_path_element) && object.is_a?(Hash)
58
- key = current_path_element[1..-1]
59
-
60
- # handle cases where one forces symbol/string keys
61
- key =
62
- if key.start_with?(":")
63
- key[1..-1].to_sym
64
- elsif key.start_with?('"') && key.end_with?('"')
65
- key[1..-2]
66
- else
67
- key.to_sym # keys should be symbols per default
68
- end
69
-
70
- if next_path_element.nil?
71
- object[key] = value
72
- elsif hash_path?(next_path_element)
73
- self.set(object[key] || object[key] = {}, remaining_path, value)
74
- elsif array_path?(next_path_element)
75
- self.set(object[key] || object[key] = [], remaining_path, value)
76
- end
77
- elsif array_path?(current_path_element) && object.is_a?(Array)
78
- if hash_path?(next_path_element)
79
- object.push(_object = {})
80
- self.set(_object, remaining_path, value)
81
- end
82
- end
83
- end
84
-
85
- #
86
- private
87
- #
88
- def self.array_depth(array)
89
- depth = 1
90
- until array == (flattend_array = array.flatten(1))
91
- depth += 1
92
- array = flattend_array
93
- end
94
-
95
- depth
96
- end
97
-
98
- def self.array_path?(path)
99
- path[0] == "["
100
- end
101
-
102
- def decode_string_or_symbol_from(string)
103
- if string.start_with?(":")
104
- string[1..-1].to_sym
105
- elsif string.start_with?('"') && string.end_with?('"')
106
- string[1..-2]
107
- else
108
- string.to_sym # defaults to symbols
109
- end
110
- end
111
-
112
- def self.hash_path?(path)
113
- path[0] == "/"
114
- end
115
-
116
- def self.split_path(path)
117
- unless path.nil?
118
- path_elements = path
119
- .gsub(/(\/)|(\[)/,
120
- "/" => " /",
121
- "[" => " [",
122
- )
123
- .split(" ")
124
-
125
- remaining_path =
126
- if path_elements.length > 1
127
- path_elements.slice(1..-1).join
128
- else
129
- nil
130
- end
131
-
132
- [path_elements.first, remaining_path]
133
- else
134
- [nil, nil]
135
- end
136
- end
5
+ require "yahm/version"
137
6
  end
@@ -60,7 +60,16 @@ class Yahm::Mapping
60
60
  end
61
61
 
62
62
  def apply_rule(rule, input_hash, output_hash)
63
- value = Yahm.get(input_hash, rule[:path])
63
+ value =
64
+ if rule[:path].is_a?(Array)
65
+ rule[:path].inject({}) do |memo, _path|
66
+ memo[_path] = Hpath.get(input_hash, _path)
67
+ memo
68
+ end
69
+ else
70
+ Hpath.get(input_hash, rule[:path])
71
+ end
72
+
64
73
  value = rule[:default] && value.nil? ? rule[:default] : value
65
74
  value = rule[:force_array] ? (value.nil? ? [] : [value].flatten(1)) : value
66
75
  value = rule[:split_by] && value.is_a?(String) ? value.split(rule[:split_by]).map!(&:strip) : value
@@ -69,7 +78,7 @@ class Yahm::Mapping
69
78
  if rule[:to].is_a?(Proc)
70
79
  instance_exec(value, output_hash, &rule[:to])
71
80
  else
72
- Yahm.set(output_hash, rule[:to], value)
81
+ Hpath.set(output_hash, rule[:to], value)
73
82
  end
74
83
  end
75
84
  end
@@ -1,3 +1,3 @@
1
1
  class Yahm
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -131,5 +131,18 @@ describe Yahm::Mapping do
131
131
  :array_length => 2
132
132
  })
133
133
  end
134
+
135
+ it "can map multiple input fields to one output field" do
136
+ mapping = Yahm::Mapping.new do
137
+ map ["/hello", "/world", "/foo"], to: "/combined", processed_by: lambda { |v| v.values.compact.join(" ") }
138
+ end
139
+
140
+ expect(mapping.apply_to({
141
+ hello: "hello",
142
+ world: "world"
143
+ })).to eq({
144
+ combined: "hello world"
145
+ })
146
+ end
134
147
  end
135
148
  end
@@ -5,89 +5,4 @@ describe Yahm do
5
5
  expect(Yahm.const_defined? :Mapping).to be_true
6
6
  expect(Yahm::Mapping.class.is_a? Class)
7
7
  end
8
-
9
- describe "#get" do
10
- let(:object) do
11
- {
12
- hello: "world",
13
- empty_array: [],
14
- empty_hash: [],
15
- "string_key" => "foobar",
16
- some: {
17
- really: [
18
- {
19
- nested: [
20
- {
21
- structure: "hello"
22
- },
23
- {
24
- structure: "world"
25
- }
26
- ]
27
- }
28
- ]
29
- },
30
- foo: [
31
- {
32
- bar: 1
33
- },
34
- {
35
- bar: 2
36
- }
37
- ],
38
- arr_of_arrs: [
39
- [ [1,2] , [3,4,5] ],
40
- [ 6,7 ],
41
- 8
42
- ]
43
- }
44
- end
45
-
46
- it "returns elements which match the given path" do
47
- expect(Yahm.get(object, "/hello")).to eq("world")
48
- expect(Yahm.get(object, "/empty_array")).to eq([])
49
- expect(Yahm.get(object, "/empty_hash")).to eq([])
50
- expect(Yahm.get(object, "/foo")).to eq([{:bar=>1}, {:bar=>2}])
51
- expect(Yahm.get(object, "/foo[0]")).to eq({:bar=>1})
52
- expect(Yahm.get(object, "/foo[1]")).to eq({:bar=>2})
53
- expect(Yahm.get(object, "/foo[]/bar")).to eq([1,2])
54
- expect(Yahm.get(object, "/arr_of_arrs[0][1][2]")).to eq([5])
55
- expect(Yahm.get(object, "/some/really[]/nested[]/structure")).to eq(["hello", "world"])
56
- expect(Yahm.get(object, "/arr_of_arrs[0]")).to eq([[1, 2], [3, 4, 5]])
57
- end
58
-
59
- it "returns nil if the path is invalid" do
60
- expect(Yahm.get(object, "/hello_world")).to eq(nil)
61
- expect(Yahm.get(object, "/foo[3]")).to eq(nil)
62
- expect(Yahm.get(object, "/foo[]/bar/muff")).to eq(nil)
63
- expect(Yahm.get(object, "/foo[]/bar[0]")).to eq(nil)
64
- end
65
-
66
- it "allows specification of the key type using : or \"\"" do
67
- expect(Yahm.get(object, '/"string_key"')).to eq("foobar")
68
- expect(Yahm.get(object, '/:string_key"')).to eq(nil)
69
- expect(Yahm.get(object, "/string_key")).to eq("foobar")
70
- end
71
- end
72
-
73
- describe "#set" do
74
- it "sets the objects value according to path and value" do
75
- Yahm.set(object = {}, "/foo[]/bar", [1,2,3])
76
- expect(object).to eq({:foo=>[{:bar=>[1, 2, 3]}]})
77
- end
78
-
79
- it "allows specification of the key type using : or \"\"" do
80
- Yahm.set(object = {}, "/:foo/\"bar\"", "foobar")
81
- expect(object).to eq({:foo=>{"bar"=>"foobar"}})
82
- end
83
-
84
- it "extends existing arrays/hashes if present" do
85
- Yahm.set(object = { foo: [{bar: [1,2,3]}] }, "/foo[]/bar", [4,5,6])
86
- expect(object).to eq({:foo=>[{:bar=>[1, 2, 3]}, {:bar=>[4, 5, 6]}]})
87
-
88
- Yahm.set(object = { foo: "bar" }, "/muff", "muffmuff")
89
- expect(object).to eq({:foo=>"bar", :muff=>"muffmuff"})
90
- end
91
-
92
- end
93
8
  end
@@ -7,7 +7,6 @@ Gem::Specification.new do |spec|
7
7
  spec.name = "yahm"
8
8
  spec.version = Yahm::VERSION
9
9
  spec.authors = ["Michael Sievers"]
10
- spec.email = ["m.sievers@ub.uni-paderborn.de"]
11
10
  spec.summary = %q{Yet another ruby hash mapper}
12
11
  spec.homepage = "https://github.com/ubpb/yahm"
13
12
  spec.license = "MIT"
@@ -17,6 +16,7 @@ Gem::Specification.new do |spec|
17
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
17
  spec.require_paths = ["lib"]
19
18
 
19
+ spec.add_dependency "hpath", ">= 0.0.5"
20
20
  spec.add_dependency "thread", ">= 0.1.4"
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.5"
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yahm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Sievers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-03 00:00:00.000000000 Z
11
+ date: 2014-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: hpath
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.5
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: thread
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -67,8 +81,7 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  description:
70
- email:
71
- - m.sievers@ub.uni-paderborn.de
84
+ email:
72
85
  executables: []
73
86
  extensions: []
74
87
  extra_rdoc_files: []