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 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
- post.doc
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
- post.card:tourism.norway.fjords$42
31
- post.card:tourism.norway.west-coast$42
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
- post.card:tourism.*$42
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
- post.*:tourism.europe.*
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
- post:tourism.europe$123
90
- post:tourism.europe.france.sightseeing$234
91
- post.card:tourism.europe.mountains$345
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
- unit|group:*
106
- ```
104
+ ```
105
+ unit|group:*
106
+ ```
107
107
 
108
- ```
109
- post.doc|card:*
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
- post:realm.label1|label2.something
118
- ```
116
+ ```
117
+ post:realm.label1|label2.something
118
+ ```
119
119
 
120
120
  The following is not allowed:
121
121
 
122
- ```
123
- post:realm1|realm2.*
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
- post:realm.*$a|b|c|d|e|f|g
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
- post:realm.*$a,post:realm.*$b,post:realm.*$c,post:realm.*$d,post:realm.*$e,post:realm.*$f,post:realm.*$g,
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
- post:realm.europe.^norway.fjords.food
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
- post:realm.europe
152
- post:realm.europe.norway
153
- post:realm.europe.norway.fjords
154
- post:realm.europe.norway.fjords.food
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
- uid = Pebbles::Uid.new('post.card:tourism.norway.fjords$1234')
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
- uid.realm
179
- => "tourism"
190
+ uid.oid
191
+ => 1234
180
192
 
181
- uid.genus
182
- => "post.card"
193
+ uid.to_s
194
+ => 'post.card:tourism.norway.fjords$1234'
183
195
 
184
- uid.species
185
- => "card"
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
- uid.path
188
- => "tourism.norway.fjords"
202
+ ```
203
+ query = Pebbles::Uid::Query.new('post.card:tourism.^norway.fjords|mountains.*')
189
204
 
190
- uid.oid
191
- => 1234
205
+ query.list?
206
+ => false
192
207
 
193
- uid.to_s
194
- => 'post.card:tourism.norway.fjords$1234'
208
+ query.collection?
209
+ => true
195
210
 
196
- uid.to_hash
197
- => {'genus_0' => 'post', 'genus_1' => 'card', 'path_0' => 'tourism', 'path_1' => 'norway', 'path_2' => 'fjords', 'oid' => '1234'}
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
@@ -17,8 +17,8 @@ module Pebbles
17
17
  [genus, path, oid.empty? ? nil : oid]
18
18
  end
19
19
 
20
- def query(s)
21
- Pebbles::Uid::Query.new(s)
20
+ def query(s, options = {})
21
+ Pebbles::Uid::Query.new(s, options)
22
22
  end
23
23
 
24
24
  def genus(s)
@@ -2,12 +2,16 @@ module Pebbles
2
2
  class Uid
3
3
  class Labels
4
4
 
5
- attr_reader :values, :name
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(options = {})
51
- Conditions.new(values, {:name => name}.merge(options)).to_hash
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
@@ -2,16 +2,26 @@ module Pebbles
2
2
  class Uid
3
3
  class Query
4
4
 
5
- attr_reader :term, :terms, :genus, :path, :oid
6
- def initialize(term)
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
- hash = hash.merge(:oid => oid) if oid?
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 ||= Labels.new(genus, :name => 'genus')
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 ||= Labels.new(path, :name => 'path')
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
@@ -1,5 +1,5 @@
1
1
  module Pebbles
2
2
  class Uid
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
  end
5
5
  end
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(:terms) { should eq(['post:area51$abc', 'post:area51$xyz']) }
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
@@ -7,7 +7,7 @@ describe Pebbles::Uid do
7
7
  describe "query" do
8
8
  it "returns a query object" do
9
9
  s = 'post:tourism.*$*'
10
- Pebbles::Uid::Query.should_receive(:new).with s
10
+ Pebbles::Uid::Query.should_receive(:new).with s, {}
11
11
  query = Pebbles::Uid.query(s)
12
12
  end
13
13
  end
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.3
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 00:00:00.000000000 Z
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: &70108731034840 !ruby/object:Gem::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: *70108731034840
24
+ version_requirements: *70099323387380
25
25
  description: Handle pebble UIDs conveniently.
26
26
  email:
27
27
  - katrina.owen@gmail.com