pebbles-uid 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +81 -65
- data/lib/pebbles-uid.rb +2 -2
- data/lib/pebbles-uid/labels.rb +24 -3
- data/lib/pebbles-uid/query.rb +43 -6
- data/lib/pebbles-uid/version.rb +1 -1
- data/spec/labels_spec.rb +9 -0
- data/spec/query_spec.rb +28 -2
- data/spec/uid_spec.rb +1 -1
- metadata +4 -4
data/README.md
CHANGED
@@ -15,7 +15,7 @@ The first label uniquely identifies which pebble the resource originated from.
|
|
15
15
|
Any secondary labels are grouped into a `species`, which identify sub-types within a given pebble.
|
16
16
|
|
17
17
|
```
|
18
|
-
|
18
|
+
post.doc
|
19
19
|
```
|
20
20
|
|
21
21
|
Here the genus is `post`, and the species is `doc`.
|
@@ -26,10 +26,10 @@ The path is a dot-delimited set of labels. The first label represents the realm,
|
|
26
26
|
|
27
27
|
A single resource may have multiple paths (and therefore multiple uids). For example:
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
```
|
30
|
+
post.card:tourism.norway.fjords$42
|
31
|
+
post.card:tourism.norway.west-coast$42
|
32
|
+
```
|
33
33
|
|
34
34
|
### Oid
|
35
35
|
|
@@ -51,9 +51,9 @@ Across the pebblestack universe, you can query for a specific resource by passin
|
|
51
51
|
|
52
52
|
In addition, the wildcard query `genus:realm.*$oid` will identify a single resource, e.g.:
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
```
|
55
|
+
post.card:tourism.*$42
|
56
|
+
```
|
57
57
|
|
58
58
|
If a specific resource is targeted (i.e. genus and oid are both unambiguous), then realm is required.
|
59
59
|
|
@@ -63,33 +63,33 @@ If a specific resource is targeted (i.e. genus and oid are both unambiguous), th
|
|
63
63
|
|
64
64
|
The most permissive query consists of any genus in any path, with any oid (implied):
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
```
|
67
|
+
*:*
|
68
|
+
```
|
69
69
|
|
70
70
|
This is the equivalent to:
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
```
|
73
|
+
*:*$*
|
74
|
+
```
|
75
75
|
|
76
76
|
Queries may not be made across multiple realms at one time. If realm is not specified in the path, then it is assumed that the application verifies realm if necessary.
|
77
77
|
|
78
78
|
In the context of a genus or a path, you may specify any number of labels and terminate with an asterisk, which means: zero or more labels follow. E.g.:
|
79
79
|
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
```
|
81
|
+
post.*:tourism.europe.*
|
82
|
+
```
|
83
83
|
|
84
84
|
NOTE: wildcard queries on species is not yet supported.
|
85
85
|
|
86
86
|
This will return things like:
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
88
|
+
```
|
89
|
+
post:tourism.europe$123
|
90
|
+
post:tourism.europe.france.sightseeing$234
|
91
|
+
post.card:tourism.europe.mountains$345
|
92
|
+
```
|
93
93
|
|
94
94
|
Asterisks may not occur in mid-sequence. In other words, `post:tourism.*.food` will not be accepted.
|
95
95
|
|
@@ -101,39 +101,39 @@ A pipe signifies _or_.
|
|
101
101
|
|
102
102
|
This can be used in genus at any position:
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
```
|
105
|
+
unit|group:*
|
106
|
+
```
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
|
108
|
+
```
|
109
|
+
post.doc|card:*
|
110
|
+
```
|
111
111
|
|
112
112
|
In a path, this can be used in any position except the first, as the realm must be unambiguous.
|
113
113
|
|
114
114
|
Thus:
|
115
115
|
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
```
|
117
|
+
post:realm.label1|label2.something
|
118
|
+
```
|
119
119
|
|
120
120
|
The following is not allowed:
|
121
121
|
|
122
|
-
|
123
|
-
|
124
|
-
|
122
|
+
```
|
123
|
+
post:realm1|realm2.*
|
124
|
+
```
|
125
125
|
|
126
126
|
If you wish to fetch a specific list of objects, you may use the pipe to delimit oids:
|
127
127
|
|
128
|
-
|
129
|
-
|
130
|
-
|
128
|
+
```
|
129
|
+
post:realm.*$a|b|c|d|e|f|g
|
130
|
+
```
|
131
131
|
|
132
132
|
This is equivalent to the NOW deprecated comma-delimited uid query:
|
133
133
|
|
134
|
-
|
135
|
-
|
136
|
-
|
134
|
+
```
|
135
|
+
post:realm.*$a,post:realm.*$b,post:realm.*$c,post:realm.*$d,post:realm.*$e,post:realm.*$f,post:realm.*$g,
|
136
|
+
```
|
137
137
|
|
138
138
|
NOTE: realm is required in this case, because each term in the list must refer to a single resource.
|
139
139
|
|
@@ -141,19 +141,18 @@ NOTE: realm is required in this case, because each term in the list must refer t
|
|
141
141
|
|
142
142
|
In both genus and paths, a caret indicates ancestry up to the specified point:
|
143
143
|
|
144
|
-
|
145
|
-
|
146
|
-
|
144
|
+
```
|
145
|
+
post:realm.europe.^norway.fjords.food
|
146
|
+
```
|
147
147
|
|
148
148
|
This represents everything at the following locations:
|
149
149
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
150
|
+
```
|
151
|
+
post:realm.europe
|
152
|
+
post:realm.europe.norway
|
153
|
+
post:realm.europe.norway.fjords
|
154
|
+
post:realm.europe.norway.fjords.food
|
155
|
+
```
|
157
156
|
|
158
157
|
## Installation
|
159
158
|
|
@@ -173,28 +172,45 @@ Or install it yourself as:
|
|
173
172
|
|
174
173
|
### Identifying an existing resource
|
175
174
|
|
176
|
-
|
175
|
+
```
|
176
|
+
uid = Pebbles::Uid.new('post.card:tourism.norway.fjords$1234')
|
177
|
+
|
178
|
+
uid.realm
|
179
|
+
=> "tourism"
|
180
|
+
|
181
|
+
uid.genus
|
182
|
+
=> "post.card"
|
183
|
+
|
184
|
+
uid.species
|
185
|
+
=> "card"
|
186
|
+
|
187
|
+
uid.path
|
188
|
+
=> "tourism.norway.fjords"
|
177
189
|
|
178
|
-
|
179
|
-
|
190
|
+
uid.oid
|
191
|
+
=> 1234
|
180
192
|
|
181
|
-
|
182
|
-
|
193
|
+
uid.to_s
|
194
|
+
=> 'post.card:tourism.norway.fjords$1234'
|
183
195
|
|
184
|
-
|
185
|
-
|
196
|
+
uid.to_hash
|
197
|
+
=> {'genus_0' => 'post', 'genus_1' => 'card', 'path_0' => 'tourism', 'path_1' => 'norway', 'path_2' => 'fjords', 'oid' => '1234'}
|
198
|
+
```
|
199
|
+
|
200
|
+
### Uid Queries
|
186
201
|
|
187
|
-
|
188
|
-
|
202
|
+
```
|
203
|
+
query = Pebbles::Uid::Query.new('post.card:tourism.^norway.fjords|mountains.*')
|
189
204
|
|
190
|
-
|
191
|
-
|
205
|
+
query.list?
|
206
|
+
=> false
|
192
207
|
|
193
|
-
|
194
|
-
|
208
|
+
query.collection?
|
209
|
+
=> true
|
195
210
|
|
196
|
-
|
197
|
-
|
211
|
+
query.to_hash
|
212
|
+
=> {'genus_0' => 'post', 'genus_1' => 'card', 'path_0' => 'tourism', 'path_1' => ['norway', nil], ['fjords', 'mountains', nil]}
|
213
|
+
```
|
198
214
|
|
199
215
|
## TODO
|
200
216
|
|
data/lib/pebbles-uid.rb
CHANGED
data/lib/pebbles-uid/labels.rb
CHANGED
@@ -2,12 +2,16 @@ module Pebbles
|
|
2
2
|
class Uid
|
3
3
|
class Labels
|
4
4
|
|
5
|
-
|
5
|
+
NO_MARKER = Class.new
|
6
|
+
|
7
|
+
attr_reader :values, :name, :suffix, :stop
|
6
8
|
def initialize(*values)
|
7
9
|
options = values.pop if values.last.is_a?(Hash)
|
8
10
|
options ||= {}
|
9
11
|
@values = values.flatten.compact.map {|v| v.split('.') }.flatten
|
10
12
|
@name = options[:name]
|
13
|
+
@suffix = options[:suffix]
|
14
|
+
@stop = options.fetch(:stop) { NO_MARKER }
|
11
15
|
end
|
12
16
|
|
13
17
|
def first
|
@@ -47,8 +51,25 @@ module Pebbles
|
|
47
51
|
!!(value =~ /[\*\|\^]/)
|
48
52
|
end
|
49
53
|
|
50
|
-
def to_hash
|
51
|
-
|
54
|
+
def to_hash
|
55
|
+
conditions.to_hash
|
56
|
+
end
|
57
|
+
|
58
|
+
def next_label
|
59
|
+
conditions.next
|
60
|
+
end
|
61
|
+
|
62
|
+
def conditions
|
63
|
+
unless @conditions
|
64
|
+
options = {:name => name, :suffix => suffix}
|
65
|
+
options.merge!(:stop => stop) if use_stop_marker?
|
66
|
+
@conditions = Conditions.new(values, options)
|
67
|
+
end
|
68
|
+
@conditions
|
69
|
+
end
|
70
|
+
|
71
|
+
def use_stop_marker?
|
72
|
+
stop != NO_MARKER
|
52
73
|
end
|
53
74
|
|
54
75
|
end
|
data/lib/pebbles-uid/query.rb
CHANGED
@@ -2,16 +2,26 @@ module Pebbles
|
|
2
2
|
class Uid
|
3
3
|
class Query
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
NO_MARKER = Class.new
|
6
|
+
|
7
|
+
attr_reader :term, :terms, :genus, :path, :oid,
|
8
|
+
:genus_name, :path_name, :suffix, :stop
|
9
|
+
def initialize(term, options = {})
|
7
10
|
@term = term
|
11
|
+
@genus_name = options.fetch(:genus) { 'genus' }
|
12
|
+
@path_name = options.fetch(:path) { 'path' }
|
13
|
+
@suffix = options[:suffix]
|
14
|
+
@stop = options.fetch(:stop) { NO_MARKER }
|
8
15
|
|
9
16
|
if wildcard_query?
|
10
17
|
@terms = [term]
|
11
|
-
@genus, @path, @oid = Pebbles::Uid.parse(term)
|
12
18
|
else
|
13
19
|
@terms = extract_terms
|
14
20
|
end
|
21
|
+
|
22
|
+
if !list?
|
23
|
+
@genus, @path, @oid = Pebbles::Uid.parse(term)
|
24
|
+
end
|
15
25
|
end
|
16
26
|
|
17
27
|
def for_one?
|
@@ -22,6 +32,13 @@ module Pebbles
|
|
22
32
|
terms.size != 1
|
23
33
|
end
|
24
34
|
|
35
|
+
def list
|
36
|
+
if !list?
|
37
|
+
raise "Cannot expand non-list query"
|
38
|
+
end
|
39
|
+
terms
|
40
|
+
end
|
41
|
+
|
25
42
|
def collection?
|
26
43
|
wildcard_query?
|
27
44
|
end
|
@@ -56,18 +73,35 @@ module Pebbles
|
|
56
73
|
end
|
57
74
|
|
58
75
|
hash = genus_wrapper.to_hash.merge(path_wrapper.to_hash)
|
59
|
-
|
76
|
+
if oid?
|
77
|
+
oid_key = ['oid', suffix].compact.join('_').to_sym
|
78
|
+
hash = hash.merge(oid_key => oid)
|
79
|
+
end
|
60
80
|
hash
|
61
81
|
end
|
62
82
|
|
83
|
+
def next_path_label
|
84
|
+
path_wrapper.next_label
|
85
|
+
end
|
86
|
+
|
63
87
|
private
|
64
88
|
|
65
89
|
def genus_wrapper
|
66
|
-
@genus_wrapper
|
90
|
+
unless @genus_wrapper
|
91
|
+
options = {:name => genus_name, :suffix => suffix}
|
92
|
+
options.merge!(:stop => stop) if use_stop_marker?
|
93
|
+
@genus_wrapper = Labels.new(genus, options)
|
94
|
+
end
|
95
|
+
@genus_wrapper
|
67
96
|
end
|
68
97
|
|
69
98
|
def path_wrapper
|
70
|
-
@path_wrapper
|
99
|
+
unless @path_wrapper
|
100
|
+
options = {:name => path_name, :suffix => suffix}
|
101
|
+
options.merge!(:stop => stop) if use_stop_marker?
|
102
|
+
@path_wrapper = Labels.new(path, options)
|
103
|
+
end
|
104
|
+
@path_wrapper
|
71
105
|
end
|
72
106
|
|
73
107
|
def wildcard_query?
|
@@ -102,6 +136,9 @@ module Pebbles
|
|
102
136
|
end.flatten
|
103
137
|
end
|
104
138
|
|
139
|
+
def use_stop_marker?
|
140
|
+
stop != NO_MARKER
|
141
|
+
end
|
105
142
|
end
|
106
143
|
end
|
107
144
|
end
|
data/lib/pebbles-uid/version.rb
CHANGED
data/spec/labels_spec.rb
CHANGED
@@ -13,6 +13,15 @@ describe Pebbles::Uid::Labels do
|
|
13
13
|
subject.size.should eq(3)
|
14
14
|
end
|
15
15
|
|
16
|
+
it "knows the next label" do
|
17
|
+
subject.next_label.should eq(:thing_3)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can use a suffix on the hash" do
|
21
|
+
uid = Pebbles::Uid::Labels.new('a.b.c', :name => 'whatevs', :suffix => 'hey')
|
22
|
+
uid.to_hash.should eq(:whatevs_0_hey => 'a', :whatevs_1_hey => 'b', :whatevs_2_hey => 'c')
|
23
|
+
end
|
24
|
+
|
16
25
|
describe "alternate constructors" do
|
17
26
|
it { Pebbles::Uid::Labels.new('a', 'b', 'c').to_s.should eq('a.b.c') }
|
18
27
|
it { Pebbles::Uid::Labels.new(['a', 'b', 'c']).to_s.should eq('a.b.c') }
|
data/spec/query_spec.rb
CHANGED
@@ -9,7 +9,7 @@ describe Pebbles::Uid::Query do
|
|
9
9
|
|
10
10
|
context "for a single resource" do
|
11
11
|
let(:term) { "post:area51$abc" }
|
12
|
-
subject { Pebbles::Uid::Query.new(term) }
|
12
|
+
subject { Pebbles::Uid::Query.new(term, :suffix => '') }
|
13
13
|
|
14
14
|
its(:term) { should == term }
|
15
15
|
|
@@ -17,6 +17,7 @@ describe Pebbles::Uid::Query do
|
|
17
17
|
its(:list?) { should == false }
|
18
18
|
its(:collection?) { should == false }
|
19
19
|
its(:cache_keys) { should eq(['post:area51.*$abc']) }
|
20
|
+
its(:to_hash) { should eq(:genus_0_ => 'post', :path_0_ => 'area51', :oid_ => 'abc') }
|
20
21
|
|
21
22
|
it "handles a wildcard path if realm is given" do
|
22
23
|
query = Pebbles::Uid::Query.new('post:area51.*$abc')
|
@@ -32,6 +33,10 @@ describe Pebbles::Uid::Query do
|
|
32
33
|
->{ Pebbles::Uid::Query.new('post:*$abc') }.should raise_error(ArgumentError)
|
33
34
|
->{ Pebbles::Uid::Query.new('post:$abc') }.should raise_error(ArgumentError)
|
34
35
|
end
|
36
|
+
|
37
|
+
it "doesn't have a list of uids" do
|
38
|
+
->{ subject.list }.should raise_error StandardError
|
39
|
+
end
|
35
40
|
end
|
36
41
|
|
37
42
|
context "for a list of resources" do
|
@@ -47,7 +52,7 @@ describe Pebbles::Uid::Query do
|
|
47
52
|
context "by oid" do
|
48
53
|
subject { Pebbles::Uid::Query.new("post:area51$abc|xyz") }
|
49
54
|
|
50
|
-
its(:
|
55
|
+
its(:list) { should eq(['post:area51$abc', 'post:area51$xyz']) }
|
51
56
|
|
52
57
|
it "can't do hashes under these circumstances" do
|
53
58
|
->{ subject.to_hash }.should raise_error(RuntimeError)
|
@@ -101,6 +106,10 @@ describe Pebbles::Uid::Query do
|
|
101
106
|
its(:oid?) { should == false }
|
102
107
|
|
103
108
|
its(:to_hash) { should == {} }
|
109
|
+
|
110
|
+
it "doesn't have a list of uids" do
|
111
|
+
->{ subject.list }.should raise_error StandardError
|
112
|
+
end
|
104
113
|
end
|
105
114
|
|
106
115
|
context "everything, with any oid" do
|
@@ -140,6 +149,23 @@ describe Pebbles::Uid::Query do
|
|
140
149
|
its(:to_hash) { should == {:oid => 'yak'} }
|
141
150
|
end
|
142
151
|
|
152
|
+
context "a typical search" do
|
153
|
+
subject { Pebbles::Uid::Query.new('beast:myths.*', :genus => 'klass', :path => 'label', :suffix => '') }
|
154
|
+
its(:to_hash) { should == {:klass_0_ => 'beast', :label_0_ => 'myths'} }
|
155
|
+
its(:next_path_label) { should == :label_1_ }
|
156
|
+
end
|
157
|
+
|
158
|
+
context "with a wildcard path" do
|
159
|
+
subject { Pebbles::Uid::Query.new('beast:myths.scary') }
|
160
|
+
its(:for_one?) { should == false }
|
161
|
+
its(:collection?) { should == true }
|
162
|
+
end
|
163
|
+
|
164
|
+
context "a search with stops" do
|
165
|
+
subject { Pebbles::Uid::Query.new('beast:myths$*', :genus => 'klass', :path => 'label', :suffix => '', :stop => nil) }
|
166
|
+
its(:to_hash) { should == {:klass_0_ => 'beast', :klass_1_ => nil, :label_0_ => 'myths', :label_1_ => nil} }
|
167
|
+
its(:next_path_label) { should == :label_1_ }
|
168
|
+
end
|
143
169
|
end
|
144
170
|
|
145
171
|
end
|
data/spec/uid_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pebbles-uid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70099323387380 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70099323387380
|
25
25
|
description: Handle pebble UIDs conveniently.
|
26
26
|
email:
|
27
27
|
- katrina.owen@gmail.com
|