pebblebed 0.0.4 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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