pebblebed 0.0.4 → 0.0.6

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.
data/README.md ADDED
@@ -0,0 +1,155 @@
1
+ Pebblebed
2
+ =========
3
+
4
+ This gem contains a number of tools for ruby that wants to be a good pebble.
5
+
6
+ Usage
7
+ =====
8
+
9
+ In your Gemfile:
10
+
11
+ gem "pebblebed"
12
+
13
+
14
+ Sinatra
15
+ =======
16
+
17
+ Pebblebed provides a lot of its functionality as a Sinatra extension which is useful for Sinatra
18
+ apps that need to talk to other pebbles - or to conform to the basic pebble-spec.
19
+
20
+ In you app:
21
+
22
+ require "pebblebed/sinatra"
23
+
24
+ class MyPebbleV1 < Sinatra::Base
25
+ register Sinatra::Pebblebed
26
+
27
+ # Declare the name of this pebble
28
+ i_am :my_pebble
29
+
30
+ # Declare which pebbles I need to talk to
31
+ declare_pebbles do
32
+ service :checkpoint, :version => 1
33
+ service :parlor, :version => 1
34
+ end
35
+
36
+ ... your stuff ...
37
+
38
+ end
39
+
40
+ The extension provide a helper method `pebbles` that can be used to talk to the declared pebbles in this
41
+ manner:
42
+
43
+ pebbles.checkpoint.get("/identities/me")
44
+
45
+ If the result is valid json, it is parsed and wrapped as a [DeepStruct](https://github.com/simen/deepstruct) record.
46
+ Otherwise it is returned as a string. If an error is returned by the server, the `Pebblebed::HttpError` exception is raised.
47
+ This exception has the fields `status` and `message`.
48
+
49
+ Other helper methods provided by this extension:
50
+
51
+ part(partspec, params = {}) # Include a part from a kit (See https://github.com/benglerpebbles/kits)
52
+ parts_script_include_tags # All script tags required by the kits
53
+ parts_stylesheet_include_tags # All stylesheet-tags required by the kits
54
+ current_session # The hash string that identifies the current browser session
55
+ pebbles # Common entrypoint for the Pebblebed::Connector
56
+ current_identity # Returns the a DeepStruct record with the vital data for the current user
57
+ require_identity # Halts with 403 if there is no current user
58
+ current_identity_is?(identity_id) # Halts with 403 if the current user is neither the provided user or a god
59
+ require_god # Halts with 403 if the current user is not a god
60
+ require_parameters(parameters, *keys) # Halts with 409 if the at least one of the provided keys is not in the params-hash
61
+
62
+
63
+ Not Sinatra
64
+ ===========
65
+
66
+ If you want to talk to pebbles from other ruby projects, you may use the Pebblebed::Connector directly. To set it up:
67
+
68
+ Pebblebed.config do
69
+ host "mypebbleapp.org" # The host where all your pebbles are mapped
70
+ service :checkpoint, :version => 1
71
+ service :grove, :version => 1
72
+ end
73
+
74
+ To create a connector do this:
75
+
76
+ pebbles = Pebblebed::Connector.new(optional_session_hash)
77
+
78
+ If you need to "be" a specific user when you talk to the pebbles you need a session from checkpoint. You provide this
79
+ to your connector when you create it and connector will take care of propagating this information to any pebble you
80
+ talk to. If you don't plan on doing any authorized request you can omit the session hash.
81
+
82
+ Then you can start making requests:
83
+
84
+ pebbles.checkpoint.get("/identities/1")
85
+ pebbles.grove.post("/posts/post:mittap.blogs.blog1", :post => {:document => {:body => "This is my blog post"}})
86
+
87
+ Uid
88
+ ===
89
+
90
+ Objects in the Pebblesphere are identified using Uids which must be unique across the whole pebblesphere. The Uid
91
+ consists of three parts: The klass of the object, the path and the object id. The format is like this:
92
+
93
+ klass:path.of.the.object$object_id
94
+
95
+ ## Klass
96
+
97
+ The `klass` specifies the type of the object. The klass of the object must map to exactly one pebble that has
98
+ the responsibility of maintining that specific klass of objects. Currently Parlor maintains `topic` and `comment`,
99
+ Checkpoint maintains `identity`, `account` and `session`, Grove maintains `post` and Origami maintains `organization`,
100
+ `associate` and more. (Presently there is no registry of which klass belongs in which pebble.)
101
+
102
+ ## Path
103
+
104
+ The three first nodes of the paths have defined uses:
105
+
106
+ The first is the `realm` of the object. A realm corresponds
107
+ to one installation of an application and no data is supposed to leak between realms. E.g. checkpoint maintains
108
+ a separate list of identities and accounts for each realm, and no identity from one realm is able to log in to another
109
+ realm.
110
+
111
+ The second node is the `box`. It roughly corresponds to a 'site' or 'location' in your application. It could typically be
112
+ a website or subsection of your application. E.g. 'forums', 'blogs', 'workspaces'.
113
+
114
+ The third noe is `collection` and will typically represent a blog, a forum or other closely related collection of objects.
115
+
116
+ More nodes may be supported by a pebble where applicable. Only the realm is required.
117
+
118
+ ## Object id
119
+
120
+ The object id is a pebble-internal identification and is to be treated as an opaque string by all other services except
121
+ for the pebble responsible for maintaining the specific klass. Typically the object_id will be equal to the id of the
122
+ database-record used internally by the pebble to store that specific object.
123
+
124
+ Some examples:
125
+
126
+ trackers:mittap.user1232$1983
127
+ post:dittforslag.suggestions.theme1$332
128
+ topic:playground$post:playground.blogs.blog1$1213 # The object-id can be a full uid. Not presently valid, but TODO
129
+
130
+ Pebblebed provides a class for processing uids: `Pebblebed::Uid`:
131
+
132
+ klass, path, oid = Pebblebed::Uid.parse(an_uid)
133
+
134
+ It currenty provides no help in building uids, but TODO.
135
+
136
+ Pebble Clients
137
+ ==============
138
+
139
+ When talking to pebbles, Pebblebed provides a generic http client with the common http-methods get, post, put, delete.
140
+
141
+ pebbles.grove.get("/posts/post:mittap.blogs.*")
142
+ pebbles.parlor.delete("/comments/comment:playground.forums.1$3423")
143
+
144
+ There is also a special "virtual" pebble that lets you ask all declared pebbles the same thing:
145
+
146
+ pebbles.quorum.get("/ping")
147
+
148
+ It will return a hash with each pebble as the key and the result as the value. If an error occured the value for that
149
+ pebble is a HttpError object with status and message.
150
+
151
+
152
+ For some pebbles Pebblebed may furnish a richer client with helper methods. This is implemented by sticking the
153
+ augmented client in the `/lib/pebblebed/clients` folder and naming the class `Pebblebed::<YourPebbleName>Client`. For
154
+ an example of this see `CheckpointClient` which in addition to the common http-methods provides the method `me` which
155
+ returns the logged in user and `god?` which checks whether she's a god(dess).
@@ -62,9 +62,6 @@ module Sinatra
62
62
 
63
63
  def self.registered(app)
64
64
  app.helpers(Sinatra::Pebblebed::Helpers)
65
- app.get "/ping" do
66
- "{\"name\":#{(app.service_name || 'undefined').to_s.inspect}}"
67
- end
68
65
  end
69
66
 
70
67
  def declare_pebbles(&block)
data/lib/pebblebed/uid.rb CHANGED
@@ -1,8 +1,14 @@
1
1
  module Pebblebed
2
2
  class InvalidUid < StandardError; end
3
3
  class Uid
4
- def initialize(uid)
5
- self.klass, self.path, self.oid = self.class.raw_parse(uid)
4
+ def initialize(args)
5
+ case args
6
+ when String
7
+ self.klass, self.path, self.oid = self.class.raw_parse(args)
8
+ when Hash
9
+ self.klass, self.path, self.oid = args[:klass], args[:path], args[:oid]
10
+ else raise "Invalid argument"
11
+ end
6
12
  raise InvalidUid, "Missing klass in uid" unless self.klass
7
13
  raise InvalidUid, "A valid uid must specify either path or oid" unless self.path || self.oid
8
14
  end
@@ -43,7 +49,7 @@ module Pebblebed
43
49
  end
44
50
 
45
51
  def self.valid_label?(value)
46
- !!(value =~ /^[a-zA-Z0-9_]+$/)
52
+ !!(value =~ /^[a-zA-Z0-9_-]+$/)
47
53
  end
48
54
 
49
55
  def self.valid_klass?(value)
@@ -60,7 +66,11 @@ module Pebblebed
60
66
  end
61
67
 
62
68
  def self.valid_oid?(value)
63
- self.valid_label?(value)
69
+ !value.nil? && !value.include?('/')
70
+ end
71
+
72
+ def realm
73
+ self.path.split(".").first if self.path
64
74
  end
65
75
 
66
76
  def inspect
@@ -1,3 +1,3 @@
1
1
  module Pebblebed
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.6"
3
3
  end
data/pebblebed.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
24
24
  s.add_development_dependency "simplecov"
25
25
 
26
26
  s.add_runtime_dependency "deepstruct"
27
- s.add_runtime_dependency "curb"
27
+ s.add_runtime_dependency "curb", "~> 0.8.0"
28
28
  s.add_runtime_dependency "yajl-ruby"
29
29
  s.add_runtime_dependency "queryparams"
30
30
  s.add_runtime_dependency "futurevalue"
data/spec/uid_spec.rb CHANGED
@@ -25,34 +25,74 @@ describe Pebblebed::Uid do
25
25
  uid.to_s.should eq "klass:$oid"
26
26
  end
27
27
 
28
+ it "can be created with a string" do
29
+ uid = Pebblebed::Uid.new "klass:some.path$oid"
30
+ uid.to_s.should eq "klass:some.path$oid"
31
+ end
32
+
33
+ it "can be created using parameters" do
34
+ uid = Pebblebed::Uid.new :klass => 'klass', :path => 'some.path', :oid => 'oid'
35
+ uid.to_s.should eq "klass:some.path$oid"
36
+ end
37
+
38
+ it "raises an error if parameter is neither string or hash" do
39
+ lambda {Pebblebed::Uid.new([])}.should raise_exception
40
+ end
41
+
28
42
  it "raises an exception when you try to create an invalid uid" do
29
43
  -> { Pebblebed::Uid.new("!:$298") }.should raise_error Pebblebed::InvalidUid
30
44
  end
31
45
 
32
- it "raises an exception when you modify an uid with an invalid value" do
46
+ it "raises an exception when you modify a uid with an invalid value" do
33
47
  uid = Pebblebed::Uid.new("klass:path$oid")
34
48
  -> { uid.klass = "!" }.should raise_error Pebblebed::InvalidUid
35
49
  -> { uid.path = "..." }.should raise_error Pebblebed::InvalidUid
36
- -> { uid.oid = "(/&%$" }.should raise_error Pebblebed::InvalidUid
50
+ -> { uid.oid = "/" }.should raise_error Pebblebed::InvalidUid
51
+ end
52
+
53
+ describe "oid" do
54
+ it "is valid with pretty much anything" do
55
+ Pebblebed::Uid.valid_oid?("abc123").should be_true
56
+ Pebblebed::Uid.valid_oid?("abc123!").should be_true
57
+ Pebblebed::Uid.valid_oid?("abc 123").should be_true
58
+ end
59
+
60
+ it "cannot contain a slash" do
61
+ Pebblebed::Uid.valid_oid?("abc/123").should be_false
62
+ end
63
+
64
+ it "can contain a full uid" do
65
+ Pebblebed::Uid.new('klass:path$post:some.path$oid').oid.should eq('post:some.path$oid')
66
+ end
67
+
68
+ it "can be missing" do
69
+ Pebblebed::Uid.new('klass:path').oid.should be_nil
70
+ end
71
+
72
+ it "is not valid if it is nil" do
73
+ Pebblebed::Uid.valid_oid?(nil).should be_false
74
+ end
37
75
  end
38
76
 
39
- it "rejects invalid labels for klass and oid" do
77
+ it "rejects invalid labels for klass" do
40
78
  Pebblebed::Uid.valid_klass?("abc123").should be_true
41
79
  Pebblebed::Uid.valid_klass?("abc123!").should be_false
42
80
  Pebblebed::Uid.valid_klass?("").should be_false
43
- Pebblebed::Uid.valid_oid?("abc123").should be_true
44
- Pebblebed::Uid.valid_oid?("abc123!").should be_false
45
- Pebblebed::Uid.valid_oid?("abc 123").should be_false
46
- Pebblebed::Uid.valid_oid?("").should be_false
47
81
  end
48
82
 
49
- it "rejects invalid paths" do
50
- Pebblebed::Uid.valid_path?("abc123").should be_true
51
- Pebblebed::Uid.valid_path?("abc.123").should be_true
52
- Pebblebed::Uid.valid_path?("").should be_true
53
- Pebblebed::Uid.valid_path?("abc!.").should be_false
54
- Pebblebed::Uid.valid_path?(".").should be_false
55
- Pebblebed::Uid.valid_path?("ab. 123").should be_false
83
+ describe "path" do
84
+ it "accepts valid paths" do
85
+ Pebblebed::Uid.valid_path?("").should be_true
86
+ Pebblebed::Uid.valid_path?("abc123").should be_true
87
+ Pebblebed::Uid.valid_path?("abc.123").should be_true
88
+ Pebblebed::Uid.valid_path?("abc.de-f.123").should be_true
89
+ end
90
+
91
+ it "rejects invalid paths" do
92
+ Pebblebed::Uid.valid_path?("abc!.").should be_false
93
+ Pebblebed::Uid.valid_path?(".").should be_false
94
+ Pebblebed::Uid.valid_path?("ab. 123").should be_false
95
+ end
56
96
  end
57
97
 
58
98
  it "knows how to parse in place" do
@@ -73,4 +113,17 @@ describe Pebblebed::Uid do
73
113
  Pebblebed::Uid.valid?("a:b.c.d").should be_true
74
114
  end
75
115
 
76
- end
116
+ it "knows how to extract the realm from the path" do
117
+ Pebblebed::Uid.new("klass:realm.other.stuff$3").realm.should eq 'realm'
118
+ Pebblebed::Uid.new("klass:realm$3").realm.should eq 'realm'
119
+ Pebblebed::Uid.new("klass:realm").realm.should eq 'realm'
120
+ Pebblebed::Uid.new("klass:$3").realm.should eq nil
121
+ end
122
+
123
+ it "knows how to extract the realm from the path" do
124
+ Pebblebed::Uid.new("klass:realm.other.stuff$3").realm.should eq 'realm'
125
+ Pebblebed::Uid.new("klass:realm$3").realm.should eq 'realm'
126
+ Pebblebed::Uid.new("klass:realm").realm.should eq 'realm'
127
+ Pebblebed::Uid.new("klass:$3").realm.should eq nil
128
+ end
129
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pebblebed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-12-19 00:00:00.000000000Z
13
+ date: 2012-01-25 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
17
- requirement: &70177387541220 !ruby/object:Gem::Requirement
17
+ requirement: &70255687117880 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '0'
23
23
  type: :development
24
24
  prerelease: false
25
- version_requirements: *70177387541220
25
+ version_requirements: *70255687117880
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rake
28
- requirement: &70177387539500 !ruby/object:Gem::Requirement
28
+ requirement: &70255687116600 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
- version_requirements: *70177387539500
36
+ version_requirements: *70255687116600
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: simplecov
39
- requirement: &70177387538700 !ruby/object:Gem::Requirement
39
+ requirement: &70255687115440 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: '0'
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *70177387538700
47
+ version_requirements: *70255687115440
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: deepstruct
50
- requirement: &70177387537720 !ruby/object:Gem::Requirement
50
+ requirement: &70255687114700 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ! '>='
@@ -55,21 +55,21 @@ dependencies:
55
55
  version: '0'
56
56
  type: :runtime
57
57
  prerelease: false
58
- version_requirements: *70177387537720
58
+ version_requirements: *70255687114700
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: curb
61
- requirement: &70177387536600 !ruby/object:Gem::Requirement
61
+ requirement: &70255687113860 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
- - - ! '>='
64
+ - - ~>
65
65
  - !ruby/object:Gem::Version
66
- version: '0'
66
+ version: 0.8.0
67
67
  type: :runtime
68
68
  prerelease: false
69
- version_requirements: *70177387536600
69
+ version_requirements: *70255687113860
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: yajl-ruby
72
- requirement: &70177387536120 !ruby/object:Gem::Requirement
72
+ requirement: &70255687113180 !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
75
  - - ! '>='
@@ -77,10 +77,10 @@ dependencies:
77
77
  version: '0'
78
78
  type: :runtime
79
79
  prerelease: false
80
- version_requirements: *70177387536120
80
+ version_requirements: *70255687113180
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: queryparams
83
- requirement: &70177387535660 !ruby/object:Gem::Requirement
83
+ requirement: &70255687112460 !ruby/object:Gem::Requirement
84
84
  none: false
85
85
  requirements:
86
86
  - - ! '>='
@@ -88,10 +88,10 @@ dependencies:
88
88
  version: '0'
89
89
  type: :runtime
90
90
  prerelease: false
91
- version_requirements: *70177387535660
91
+ version_requirements: *70255687112460
92
92
  - !ruby/object:Gem::Dependency
93
93
  name: futurevalue
94
- requirement: &70177387535040 !ruby/object:Gem::Requirement
94
+ requirement: &70255687111860 !ruby/object:Gem::Requirement
95
95
  none: false
96
96
  requirements:
97
97
  - - ! '>='
@@ -99,10 +99,10 @@ dependencies:
99
99
  version: '0'
100
100
  type: :runtime
101
101
  prerelease: false
102
- version_requirements: *70177387535040
102
+ version_requirements: *70255687111860
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: pathbuilder
105
- requirement: &70177387534460 !ruby/object:Gem::Requirement
105
+ requirement: &70255687111240 !ruby/object:Gem::Requirement
106
106
  none: false
107
107
  requirements:
108
108
  - - ! '>='
@@ -110,10 +110,10 @@ dependencies:
110
110
  version: '0'
111
111
  type: :runtime
112
112
  prerelease: false
113
- version_requirements: *70177387534460
113
+ version_requirements: *70255687111240
114
114
  - !ruby/object:Gem::Dependency
115
115
  name: nokogiri
116
- requirement: &70177387533740 !ruby/object:Gem::Requirement
116
+ requirement: &70255687110520 !ruby/object:Gem::Requirement
117
117
  none: false
118
118
  requirements:
119
119
  - - ! '>='
@@ -121,10 +121,10 @@ dependencies:
121
121
  version: '0'
122
122
  type: :runtime
123
123
  prerelease: false
124
- version_requirements: *70177387533740
124
+ version_requirements: *70255687110520
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: i18n
127
- requirement: &70177387532700 !ruby/object:Gem::Requirement
127
+ requirement: &70255687109920 !ruby/object:Gem::Requirement
128
128
  none: false
129
129
  requirements:
130
130
  - - ! '>='
@@ -132,10 +132,10 @@ dependencies:
132
132
  version: '0'
133
133
  type: :runtime
134
134
  prerelease: false
135
- version_requirements: *70177387532700
135
+ version_requirements: *70255687109920
136
136
  - !ruby/object:Gem::Dependency
137
137
  name: activesupport
138
- requirement: &70177387531760 !ruby/object:Gem::Requirement
138
+ requirement: &70255687109260 !ruby/object:Gem::Requirement
139
139
  none: false
140
140
  requirements:
141
141
  - - ! '>='
@@ -143,7 +143,7 @@ dependencies:
143
143
  version: '0'
144
144
  type: :runtime
145
145
  prerelease: false
146
- version_requirements: *70177387531760
146
+ version_requirements: *70255687109260
147
147
  description: Development tools for working with Pebblebed
148
148
  email:
149
149
  - katrina@bengler.no
@@ -155,6 +155,7 @@ files:
155
155
  - .gitignore
156
156
  - .rspec
157
157
  - Gemfile
158
+ - README.md
158
159
  - Rakefile
159
160
  - lib/pebblebed.rb
160
161
  - lib/pebblebed/clients/abstract_client.rb
@@ -189,12 +190,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
189
190
  - - ! '>='
190
191
  - !ruby/object:Gem::Version
191
192
  version: '0'
193
+ segments:
194
+ - 0
195
+ hash: -441752401795012861
192
196
  required_rubygems_version: !ruby/object:Gem::Requirement
193
197
  none: false
194
198
  requirements:
195
199
  - - ! '>='
196
200
  - !ruby/object:Gem::Version
197
201
  version: '0'
202
+ segments:
203
+ - 0
204
+ hash: -441752401795012861
198
205
  requirements: []
199
206
  rubyforge_project: pebblebed
200
207
  rubygems_version: 1.8.10