yahm 0.1.0 → 0.2.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 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: []