hpath 0.0.1 → 0.0.2
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/.rspec +3 -0
- data/Gemfile +6 -1
- data/README.md +120 -2
- data/Rakefile +5 -0
- data/hpath.gemspec +5 -3
- data/lib/hpath.rb +91 -3
- data/lib/hpath/filter.rb +33 -0
- data/lib/hpath/parser.rb +105 -0
- data/lib/hpath/version.rb +1 -1
- data/spec/hpath/filter_spec.rb +15 -0
- data/spec/hpath/parser_spec.rb +26 -0
- data/spec/hpath_spec.rb +70 -0
- data/spec/spec_helper.rb +12 -0
- metadata +48 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d97f5894eb225d22238c604ab0fc4e06a31e5fa1
|
4
|
+
data.tar.gz: a52d7400d901e41584dafb8613048358cfb78a2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ed6a57ed11bd16a296a6572ea282190960f0f60ca925d7226c469c461948c9bdc89e10972fed14221316c0fa138382cabf6c10b9a05485bbcf524b1b49f3bc1
|
7
|
+
data.tar.gz: 3e0bb084b7274f51c8c53bd175ee3992f7049d3689d257f9851a31376ce88bd01cc8e6800d3a105c761869fd3e8f7fb3497b064c66b004f3f3c2abbf16368af4
|
data/.rspec
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Hpath
|
2
2
|
|
3
|
-
|
3
|
+
This code is heavy work in progress and does not work today. The examples and usage hints given below only show the goals.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,7 +18,125 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
|
21
|
+
Here are some examples of hpath in action.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
record = {
|
25
|
+
title: "About a hash",
|
26
|
+
creator: [
|
27
|
+
"Hashman",
|
28
|
+
"Hashboy"
|
29
|
+
],
|
30
|
+
price: [
|
31
|
+
{ currency: :USD, value: 12.99 },
|
32
|
+
{ currency: :EUR, value: 8.99 }
|
33
|
+
],
|
34
|
+
subject: [
|
35
|
+
{ type: "automatic", value: "hash" },
|
36
|
+
{ type: "automatic", value: "hashes" },
|
37
|
+
{ type: "automatic", value: "ruby" },
|
38
|
+
{ type: "manual", value: "hash" },
|
39
|
+
{ type: "manual", value: "array" },
|
40
|
+
{ type: "manual", value: "Hashman" },
|
41
|
+
{ type: "manual", value: "Hashboy" },
|
42
|
+
],
|
43
|
+
_source: {
|
44
|
+
"id" => "123",
|
45
|
+
"title" => "<h1>About a hash</h1>",
|
46
|
+
...
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
Hpath.get record, "/title"
|
51
|
+
# => "About a hash"
|
52
|
+
|
53
|
+
Hpath.get record, "/_source/id"
|
54
|
+
# => "123"
|
55
|
+
|
56
|
+
Hpath.get record, "/_source/[id, title]"
|
57
|
+
# => { "id" => "123", "title" => "<h1>About a hash</h1>" }
|
58
|
+
|
59
|
+
Hpath.get record, "/price/*[currency=USD]"
|
60
|
+
# => [{ currency: :USD, value: 12.99 }]
|
61
|
+
|
62
|
+
Hpath.get record, "/price/*[currency=USD,value<10]"
|
63
|
+
# => nil
|
64
|
+
|
65
|
+
Hpath.get record, "/price/*[(currency=USD|currency=EUR),value<10]"
|
66
|
+
# => [{ currency: :EUR, value: 8.99 }]
|
67
|
+
|
68
|
+
Hpath.get record, "/subject/*[type=automatic]"
|
69
|
+
# => [
|
70
|
+
# { type: "automatic", value: "hash" },
|
71
|
+
# { type: "automatic", value: "hashes" },
|
72
|
+
# { type: "automatic", value: "ruby" }
|
73
|
+
# ]
|
74
|
+
|
75
|
+
Hpath.get record, "/subject/*[type=automatic]/type"
|
76
|
+
# => ["automatic", "automatic", "automatic"]
|
77
|
+
```
|
78
|
+
|
79
|
+
## Syntax
|
80
|
+
|
81
|
+
### `/`
|
82
|
+
Get the root element.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
Hpath.get [:a,:b,:c], "/"
|
86
|
+
# => [:a,:b,:c]
|
87
|
+
```
|
88
|
+
|
89
|
+
### `/[n]`
|
90
|
+
Get the n-th element of an array.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
Hpath.get [:a,:b,:c], "/[1]"
|
94
|
+
# => :a
|
95
|
+
```
|
96
|
+
|
97
|
+
### `/[n,m,...]`
|
98
|
+
Get the n-th, m-th and ... element of an array.
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
Hpath.get [:a,:b,:c], "/[1,2]"
|
102
|
+
# => [:a,:b]
|
103
|
+
```
|
104
|
+
|
105
|
+
### `/[key1, key2, ...]`
|
106
|
+
If current element is a hash, get a hash only with the given keys. Since it cannot be determined, if the key is a symbol or a string, both interpretations are checked. If the current object is not a hash, but has methods named `key1, key2`, this methods are called and the results are returned.
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
Hpath.get {a: "b", c: "d", e: "f"}, "/[a,c]"
|
110
|
+
# => {a: "b", c: "d"}
|
111
|
+
```
|
112
|
+
|
113
|
+
### `/*`
|
114
|
+
Get all elements of the current root element. If it's a array, this simply returns the array. If it's a hash, an array of all key/value pairs is returned.
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
Hpath.get [:a,:b,:c], "/*"
|
118
|
+
# => [:a,:b,:c]
|
119
|
+
```
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
Hpath.get {a: "b", c: "d", e: "f"}, "/*"
|
123
|
+
# => [{a: "b"}, {c: "d"}, {e: "f"}]
|
124
|
+
```
|
125
|
+
|
126
|
+
### `/key`
|
127
|
+
If the current element is a hash, return the value of the given key. If the current element is not a hash, but has a method named `key`, this method is called and the result is returned.
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
Hpath.get {a: { b: "c" } }, "/a"
|
131
|
+
# => { b: "c" }
|
132
|
+
```
|
133
|
+
|
134
|
+
If the current element is an array, the non-array behaviour is applied to all members of the array.
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
Hpath.get([{a:"1", b:"2", c:"3"}, {a:"2", b:"5", c:"6"}], "/a")
|
138
|
+
# => ["1", "2"]
|
139
|
+
```
|
22
140
|
|
23
141
|
## Contributing
|
24
142
|
|
data/Rakefile
CHANGED
data/hpath.gemspec
CHANGED
@@ -1,13 +1,12 @@
|
|
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 "hpath/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "hpath"
|
8
8
|
spec.version = Hpath::VERSION
|
9
9
|
spec.authors = ["Michael Sievers"]
|
10
|
-
#spec.email = ["michael_sievers@web.de"]
|
11
10
|
spec.summary = %q{HPath for ruby}
|
12
11
|
spec.homepage = "https://github.com/hpath/hpath-ruby"
|
13
12
|
spec.license = "MIT"
|
@@ -17,6 +16,9 @@ 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 "parslet", ">= 1.6.1"
|
20
|
+
|
20
21
|
spec.add_development_dependency "bundler", "~> 1.5"
|
21
22
|
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec", ">= 3.0.0", "< 4.0.0"
|
22
24
|
end
|
data/lib/hpath.rb
CHANGED
@@ -1,5 +1,93 @@
|
|
1
|
-
require "hpath/version"
|
2
|
-
|
3
1
|
module Hpath
|
4
|
-
|
2
|
+
require "hpath/filter"
|
3
|
+
require "hpath/parser"
|
4
|
+
require "hpath/version"
|
5
|
+
|
6
|
+
def self.get(object, hpath_string)
|
7
|
+
hpath = Hpath::Parser.parse(hpath_string)
|
8
|
+
_get(object, hpath[:path])
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
private
|
13
|
+
#
|
14
|
+
def self._get(object, paths, parent = object)
|
15
|
+
_object = object
|
16
|
+
|
17
|
+
if paths.empty?
|
18
|
+
return object
|
19
|
+
else
|
20
|
+
path = paths.shift
|
21
|
+
end
|
22
|
+
|
23
|
+
if path[:identifier]
|
24
|
+
object = _resolve_identifier(object, path[:identifier])
|
25
|
+
elsif path[:axis] == "parent"
|
26
|
+
object = parent
|
27
|
+
end
|
28
|
+
|
29
|
+
if path[:indices]
|
30
|
+
object = _resolve_indices(object, path[:indices])
|
31
|
+
elsif path[:keys]
|
32
|
+
object = _resolve_keys(object, path[:keys])
|
33
|
+
end
|
34
|
+
|
35
|
+
unless path[:filter].nil?
|
36
|
+
object = _apply_filters(object, Hpath::Filter.new(path[:filter]))
|
37
|
+
end
|
38
|
+
|
39
|
+
self._get(object, paths, _object)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self._apply_filters(object, filter)
|
43
|
+
if object.is_a?(Array)
|
44
|
+
object.select do |element|
|
45
|
+
filter.applies?(element)
|
46
|
+
end
|
47
|
+
else
|
48
|
+
#binding.pry
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self._resolve_identifier(object, identifier)
|
53
|
+
if object.is_a?(Array)
|
54
|
+
if identifier.to_s == "*"
|
55
|
+
object
|
56
|
+
else
|
57
|
+
object.map do |element|
|
58
|
+
if element.is_a?(Hash)
|
59
|
+
element[identifier.to_s] || element[identifier.to_sym]
|
60
|
+
elsif element.respond_to?(identifier)
|
61
|
+
element.send(identifier)
|
62
|
+
else
|
63
|
+
raise "Cannot apply identifier to collection object!"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
elsif object.is_a?(Hash)
|
68
|
+
if identifier.to_s == "*"
|
69
|
+
object.map { |key, value| {key => value} }
|
70
|
+
else
|
71
|
+
object[identifier.to_s] || object[identifier.to_sym]
|
72
|
+
end
|
73
|
+
else
|
74
|
+
#binding.pry
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self._resolve_indices(object, indices)
|
79
|
+
if indices.length == 1
|
80
|
+
object[indices.first]
|
81
|
+
else
|
82
|
+
indices.map { |index| object[index] }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self._resolve_keys(object, keys)
|
87
|
+
if object.is_a?(Hash)
|
88
|
+
object.select { |key, value| keys.include?(key.to_s) || keys.include?(key.to_sym) }
|
89
|
+
else
|
90
|
+
raise "Cannot resolve keys for non-hash objects!"
|
91
|
+
end
|
92
|
+
end
|
5
93
|
end
|
data/lib/hpath/filter.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class Hpath::Filter
|
2
|
+
|
3
|
+
def initialize(filter_hash)
|
4
|
+
@type = filter_hash.keys.first
|
5
|
+
|
6
|
+
if @type == :and_filter || @type == :or_filter
|
7
|
+
@children = filter_hash.values.first.map do |element|
|
8
|
+
Hpath::Filter.new(element)
|
9
|
+
end
|
10
|
+
elsif @type == :key_value_filter
|
11
|
+
@key = filter_hash[:key_value_filter][:key]
|
12
|
+
@value = filter_hash[:key_value_filter][:value]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def applies?(object)
|
17
|
+
if @type == :and_filter
|
18
|
+
@children.all? { |child_filter| child_filter.applies?(object) }
|
19
|
+
elsif @type == :or_filter
|
20
|
+
@children.any? { |child_filter| child_filter.applies?(object) }
|
21
|
+
elsif @type == :key_value_filter
|
22
|
+
if object.is_a?(Hash) && (@value.is_a?(String) || @value.is_a?(Symbol))
|
23
|
+
object[@key.to_s] == @value.to_s || object[@key.to_sym] == @value.to_s ||
|
24
|
+
object[@key.to_s] == @value.to_sym || object[@key.to_sym] == @value.to_sym
|
25
|
+
else
|
26
|
+
if object.respond_to(@key)
|
27
|
+
object.send(@key) == @value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/hpath/parser.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require "parslet"
|
2
|
+
|
3
|
+
class Hpath::Parser
|
4
|
+
def self.parse(string)
|
5
|
+
self.new.parse(string)
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse(string)
|
9
|
+
transform(normalize(parser.parse(string)))
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
private
|
14
|
+
#
|
15
|
+
def normalize(result_tree) # to ease transformation
|
16
|
+
result_tree[:path].map! do |element|
|
17
|
+
element[:axis] ||= nil
|
18
|
+
element[:identifier] ||= nil
|
19
|
+
element[:filter] ||= nil
|
20
|
+
element[:indices] ||= nil
|
21
|
+
element[:indices] = [element[:indices]] if !element[:indices].nil? && !element[:indices].is_a?(Array)
|
22
|
+
element[:keys] ||= nil
|
23
|
+
element[:keys] = [element[:keys]] if !element[:keys].nil? && !element[:keys].is_a?(Array)
|
24
|
+
element
|
25
|
+
end
|
26
|
+
|
27
|
+
result_tree
|
28
|
+
end
|
29
|
+
|
30
|
+
def parser
|
31
|
+
@parser ||=
|
32
|
+
Class.new(Parslet::Parser) do
|
33
|
+
rule(:space) { match('\s').repeat(1) }
|
34
|
+
rule(:space?) { space.maybe }
|
35
|
+
|
36
|
+
rule(:key_value_filter) {
|
37
|
+
space? >> match['a-zA-Z'].repeat(1).maybe.as(:key) >> (str("<") | str(">") | str("=").repeat(1,3)).as(:operator) >> match['a-zA-Z0-9'].repeat(1).as(:value) >> space?
|
38
|
+
}
|
39
|
+
|
40
|
+
rule(:or_filter) {
|
41
|
+
((and_filter.as(:and_filter) | key_value_filter.as(:key_value_filter)) >> str("|")).repeat(1) >> (and_filter.as(:and_filter) | key_value_filter.as(:key_value_filter))
|
42
|
+
}
|
43
|
+
|
44
|
+
rule(:primary) {
|
45
|
+
str("(") >> or_filter.as(:or_filter) >> str(")")
|
46
|
+
}
|
47
|
+
|
48
|
+
rule(:and_filter) {
|
49
|
+
((primary | key_value_filter.as(:key_value_filter)) >>
|
50
|
+
str(",")).repeat(1) >>
|
51
|
+
(primary | key_value_filter.as(:key_value_filter))
|
52
|
+
}
|
53
|
+
|
54
|
+
rule(:filter) {
|
55
|
+
space? >> (or_filter.as(:or_filter) | and_filter.as(:and_filter) | key_value_filter.as(:key_value_filter)).as(:filter) >> space?
|
56
|
+
}
|
57
|
+
|
58
|
+
rule(:keys) {
|
59
|
+
match('[a-zA-Z0-9]').repeat(1).as(:key) >> (space? >> str(",") >> space? >> match('[a-zA-Z0-9]').repeat(1).as(:key)).repeat
|
60
|
+
}
|
61
|
+
|
62
|
+
rule(:indices) {
|
63
|
+
match('[0-9]').repeat(1).as(:index) >> (space? >> str(",") >> match('[0-9]').repeat(1).as(:index)).repeat
|
64
|
+
}
|
65
|
+
|
66
|
+
rule(:identifier) {
|
67
|
+
match('[a-zA-Z0-9*_]').repeat(1)
|
68
|
+
}
|
69
|
+
|
70
|
+
rule(:node) {
|
71
|
+
str("/") >> (identifier.as(:identifier) | (str("::") >> identifier.as(:axis))).maybe >> (str("[") >> space? >> (indices.as(:indices) | filter | keys.as(:keys)) >> space? >> str("]")).maybe
|
72
|
+
}
|
73
|
+
|
74
|
+
rule(:path) {
|
75
|
+
node.repeat(1).as(:path)
|
76
|
+
}
|
77
|
+
|
78
|
+
# root
|
79
|
+
root(:path)
|
80
|
+
end.new
|
81
|
+
end
|
82
|
+
|
83
|
+
def transform(result_tree)
|
84
|
+
transformation.apply(result_tree)
|
85
|
+
end
|
86
|
+
|
87
|
+
def transformation
|
88
|
+
@transformation ||=
|
89
|
+
Class.new(Parslet::Transform) do
|
90
|
+
rule(axis: simple(:axis), identifier: simple(:identifier), filter: subtree(:filter), indices: subtree(:indices), keys: subtree(:keys)) {
|
91
|
+
{
|
92
|
+
axis: axis.nil? ? nil : axis.to_s,
|
93
|
+
identifier: identifier.nil? ? nil : identifier.to_s,
|
94
|
+
filter: filter,
|
95
|
+
indices: indices.nil? ? nil : indices.map { |element| Integer(element[:index]) },
|
96
|
+
keys: keys.nil? ? nil : keys.map { |element| element[:key].to_s.to_sym }
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
rule(key: simple(:key), operator: simple(:operator), value: simple(:value)) {
|
101
|
+
{ key: key.nil? ? nil : key.to_sym, operator: operator.to_s, value: value.to_s }
|
102
|
+
}
|
103
|
+
end.new
|
104
|
+
end
|
105
|
+
end
|
data/lib/hpath/version.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
describe Hpath::Filter do
|
2
|
+
context "initialized with a (nested) filter hash" do
|
3
|
+
let(:filter_hash) { Hpath::Parser.new.parse("/array/*[a=b,c=d,(e=d|e=f)]")[:path].first[:filter] }
|
4
|
+
|
5
|
+
describe ".filter" do
|
6
|
+
context "when given object is an array containing hashes" do
|
7
|
+
let(:filter) { Hpath::Filter.new(Hpath::Parser.new.parse("/array/*[a=b,c=d,(e=d|e=f)]")[:path][1][:filter]) }
|
8
|
+
|
9
|
+
it "returns only hashes which match the filter" do
|
10
|
+
#w = [{a: "b", c: "d", e: "f"}, {a: "b", c: "d", e: "z"}].select { |e| filter.applies?(e) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
describe Hpath::Parser do
|
2
|
+
let(:parser) { Hpath::Parser.new }
|
3
|
+
|
4
|
+
it "parses a hpath string into a tree structure" do
|
5
|
+
=begin
|
6
|
+
expect(parser.parse("/foo/bar/*[a=b,c=d,(e<d|e>f)]/foo[1]/bar[<10]")).to eq(
|
7
|
+
{:path=>
|
8
|
+
[{:identifier=>:foo, :filter=>nil, :index=>nil},
|
9
|
+
{:identifier=>:bar, :filter=>nil, :index=>nil},
|
10
|
+
{:identifier=>:*,
|
11
|
+
:filter=>
|
12
|
+
{:and_filter=>
|
13
|
+
[{:key_value_filter=>{:key=>:a, :operator=>"=", :value=>"b"}},
|
14
|
+
{:key_value_filter=>{:key=>:c, :operator=>"=", :value=>"d"}},
|
15
|
+
{:or_filter=>
|
16
|
+
[{:key_value_filter=>{:key=>:e, :operator=>"<", :value=>"d"}},
|
17
|
+
{:key_value_filter=>{:key=>:e, :operator=>">", :value=>"f"}}]}]},
|
18
|
+
:index=>nil},
|
19
|
+
{:identifier=>:foo, :filter=>nil, :index=>1},
|
20
|
+
{:identifier=>:bar,
|
21
|
+
:filter=>{:key_value_filter=>{:key=>nil, :operator=>"<", :value=>"10"}},
|
22
|
+
:index=>nil}]}
|
23
|
+
)
|
24
|
+
=end
|
25
|
+
end
|
26
|
+
end
|
data/spec/hpath_spec.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
describe Hpath do
|
2
|
+
describe "#get" do
|
3
|
+
describe "returns the corresponding value from the given object" do
|
4
|
+
it "processes \"/key\" for a nested hash" do
|
5
|
+
hpath_result = Hpath.get({ foo: { bar: 1 } }, "/foo")
|
6
|
+
expect(hpath_result).to eq({ bar: 1 })
|
7
|
+
end
|
8
|
+
|
9
|
+
it "processes \"/[n]\" for an array" do
|
10
|
+
hpath_result = Hpath.get([1,2,3], "/[0]")
|
11
|
+
expect(hpath_result).to eq(1)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "processes \"/[m,n]\" for an array" do
|
15
|
+
hpath_result = Hpath.get([1,2,3], "/[0,1]")
|
16
|
+
expect(hpath_result).to eq([1,2])
|
17
|
+
end
|
18
|
+
|
19
|
+
it "processes \"/key1/key2\" for a nested hash" do
|
20
|
+
hpath_result = Hpath.get({ foo: { bar: 1 } }, "/foo/bar")
|
21
|
+
expect(hpath_result).to eq(1)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "processes \"/*\" for an array" do
|
25
|
+
hpath_result = Hpath.get([1,2,3], "/*")
|
26
|
+
expect(hpath_result).to eq([1,2,3])
|
27
|
+
end
|
28
|
+
|
29
|
+
it "processes \"/*\" for a hash" do
|
30
|
+
hpath_result = Hpath.get({a: "b", c: "d"}, "/*")
|
31
|
+
expect(hpath_result).to eq([{a: "b"}, {c: "d"}])
|
32
|
+
end
|
33
|
+
|
34
|
+
it "processes \"/[key1, key2]\" for a hash" do
|
35
|
+
hpath_result = Hpath.get({a: 1, b: 2, "c" => 3}, "/[a,c]")
|
36
|
+
expect(hpath_result).to eq({a: 1, "c" => 3})
|
37
|
+
end
|
38
|
+
|
39
|
+
it "processes \"/[key=value]\" for a array of hashes" do
|
40
|
+
hpath_result = Hpath.get([{a: "foo"}, {a: "bar"}, { "a" => :bar }, {a: "muff"}], "/[a=bar]")
|
41
|
+
expect(hpath_result).to eq([{:a=>"bar"}, {"a"=>:bar}])
|
42
|
+
end
|
43
|
+
|
44
|
+
it "processes \"/[key1=value1,key2=value2]\" for a array of hashes" do
|
45
|
+
hpath_result = Hpath.get([{a:"1", b:"2", c:"3"}, {"a" => "1", "b" => "2", c:"3"}, {a:"2", b:"1", c:"3"}], "/[a=1,b=2]")
|
46
|
+
expect(hpath_result).to eq([{:a=>"1", :b=>"2", :c=>"3"}, {"a"=>"1", "b"=>"2", :c=>"3"}])
|
47
|
+
end
|
48
|
+
|
49
|
+
it "processes \"/[key1=value1,(key2=value2|key3=value3)]\" for a array of hashes" do
|
50
|
+
hpath_result = Hpath.get([{a:"1", b:"2", c:"3"}, {a:"1", b:"5", c:"6"}, {a:"2", b:"1", c:"3"}], "/[a=1,(b=5|c=3)]")
|
51
|
+
expect(hpath_result).to eq([{:a=>"1", :b=>"2", :c=>"3"}, {:a=>"1", :b=>"5", :c=>"6"}])
|
52
|
+
end
|
53
|
+
|
54
|
+
it "processes \"/array/key\" for an array of hashes" do
|
55
|
+
hpath_result = Hpath.get([{a:"1", b:"2", c:"3"}, {a:"1", b:"5", c:"6"}, {a:"2", b:"1", c:"3"}], "/a")
|
56
|
+
expect(hpath_result).to eq(["1", "1", "2"])
|
57
|
+
end
|
58
|
+
|
59
|
+
it "processes \"/key1/::parent\" for a hash" do
|
60
|
+
hpath_result = Hpath.get({ foo: { bar: "foobar" } }, "/foo/::parent")
|
61
|
+
expect(hpath_result).to eq({ foo: { bar: "foobar" } })
|
62
|
+
end
|
63
|
+
|
64
|
+
it "processes \"/[n]/::parent\" for an array of hashes" do
|
65
|
+
hpath_result = Hpath.get([{ foo: { bar: "foobar" } }], "/[0]/::parent")
|
66
|
+
expect(hpath_result).to eq([{ foo: { bar: "foobar" } }])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hpath
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
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-
|
11
|
+
date: 2014-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: parslet
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.6.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.6.1
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,26 @@ dependencies:
|
|
38
52
|
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.0.0
|
62
|
+
- - "<"
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: 4.0.0
|
65
|
+
type: :development
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: 3.0.0
|
72
|
+
- - "<"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 4.0.0
|
41
75
|
description:
|
42
76
|
email:
|
43
77
|
executables: []
|
@@ -45,13 +79,20 @@ extensions: []
|
|
45
79
|
extra_rdoc_files: []
|
46
80
|
files:
|
47
81
|
- ".gitignore"
|
82
|
+
- ".rspec"
|
48
83
|
- Gemfile
|
49
84
|
- LICENSE.txt
|
50
85
|
- README.md
|
51
86
|
- Rakefile
|
52
87
|
- hpath.gemspec
|
53
88
|
- lib/hpath.rb
|
89
|
+
- lib/hpath/filter.rb
|
90
|
+
- lib/hpath/parser.rb
|
54
91
|
- lib/hpath/version.rb
|
92
|
+
- spec/hpath/filter_spec.rb
|
93
|
+
- spec/hpath/parser_spec.rb
|
94
|
+
- spec/hpath_spec.rb
|
95
|
+
- spec/spec_helper.rb
|
55
96
|
homepage: https://github.com/hpath/hpath-ruby
|
56
97
|
licenses:
|
57
98
|
- MIT
|
@@ -76,4 +117,8 @@ rubygems_version: 2.2.0
|
|
76
117
|
signing_key:
|
77
118
|
specification_version: 4
|
78
119
|
summary: HPath for ruby
|
79
|
-
test_files:
|
120
|
+
test_files:
|
121
|
+
- spec/hpath/filter_spec.rb
|
122
|
+
- spec/hpath/parser_spec.rb
|
123
|
+
- spec/hpath_spec.rb
|
124
|
+
- spec/spec_helper.rb
|