medea 0.6.6 → 0.6.7

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/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Dependencies are specified in medea.gemspec
3
+ # All dependencies are specified in medea.gemspec
4
4
  gemspec
@@ -1,6 +1,7 @@
1
1
 
2
2
  module Medea
3
3
  require 'rubygems'
4
+ require 'pr_geohash'
4
5
  require 'medea/version'
5
6
  require 'medea/inheritable_attributes'
6
7
  require 'medea/active_model_methods'
@@ -124,6 +124,9 @@ module Medea
124
124
  @__jason_data = JSON.parse response
125
125
  @__jason_etag = response.headers[:etag]
126
126
  @__jason_timestamp = response.headers[:timestamp]
127
+ if response.headers[:http_x_public]
128
+ @public = response.headers[:http_x_public].split(",")
129
+ end
127
130
  @__jason_state = :stale
128
131
  end
129
132
 
@@ -26,8 +26,12 @@ module Medea
26
26
  end
27
27
  end
28
28
 
29
- def to_url
30
- "#{@parent.to_url}/#{@attachment_name}"
29
+ def to_url mode=:secure
30
+ "#{@parent.to_url mode}/#{@attachment_name}"
31
+ end
32
+
33
+ def to_public_url
34
+ to_url :public
31
35
  end
32
36
 
33
37
  def load_from_jasondb
@@ -19,8 +19,12 @@ module JasonDB
19
19
  host = "rest.jasondb.com"
20
20
  end
21
21
  protocol = "http"
22
- protocol << "s" if mode == :secure
23
- "#{protocol}://#{user}:#{password}@#{host}/#{topic}/"
22
+ if mode == :secure
23
+ protocol << "s"
24
+ "#{protocol}://#{user}:#{password}@#{host}/#{topic}/"
25
+ else #mode == :public
26
+ "#{protocol}://#{host}/#{topic}/"
27
+ end
24
28
  end
25
29
 
26
30
  end
@@ -23,9 +23,10 @@ module Medea
23
23
 
24
24
  def method_missing name, *args, &block
25
25
  #is this a list property on the base class?
26
- if (@type.class_variable_defined? :@@lists) && (@type.send(:class_variable_get, :@@lists).has_key? name)
26
+ lists = @type.class_variable_defined?(:@@opts) ? (@type.class_variable_get :@@opts)[:lists] : nil
27
+ if lists && lists.has_key?(name)
27
28
  #if so, we'll just return a new ListProperty with my query as the parent
28
- new_list_class, new_list_type = @type.send(:class_variable_get, :@@lists)[name]
29
+ new_list_class, new_list_type = lists[name]
29
30
  base_query = self.clone
30
31
  base_query.result_format = :keylist
31
32
  JasonListProperty.new base_query, name.to_sym, new_list_class, new_list_type
@@ -7,6 +7,9 @@ module Medea
7
7
 
8
8
  class JasonObject < JasonBase
9
9
 
10
+ #these verbs are able to be made public
11
+ HTTP_VERBS = [:GET, :POST, :PUT, :DELETE]
12
+
10
13
  include Medea::ActiveModelMethods
11
14
  if defined? ActiveModel
12
15
  extend ActiveModel::Naming
@@ -18,8 +21,7 @@ module Medea
18
21
 
19
22
  #Here we're going to put the "query" interface
20
23
 
21
- #create a JasonDeferredQuery with no conditions, other than HTTP_X_CLASS=self.name
22
- #if mode is set to :eager, we create the JasonDeferredQuery, invoke it's execution and then return it
24
+ #create a JasonDeferredQuery for all records of this class & with some optional conditions
23
25
  def JasonObject.all(opts=nil)
24
26
  q = JasonDeferredQuery.new :class => self, :filters => {:VERSION0 => nil, :FILTER => {:HTTP_X_CLASS => self, :HTTP_X_ACTION => :POST}}
25
27
  if opts && opts[:limit]
@@ -112,12 +114,17 @@ module Medea
112
114
 
113
115
  def initialize initialiser = nil, mode = :eager
114
116
  @attachments = {}
115
- if self.class.class_variable_defined? :@@attachments
116
- (self.class.class_variable_get :@@attachments).each do |k|
117
+ if opts[:attachments]
118
+ opts[:attachments].each do |k|
117
119
  @attachments[k] = nil
118
120
  end
119
121
  end
120
122
 
123
+ @public = []
124
+ if opts[:public]
125
+ opts[:public].each {|i| @public << i}
126
+ end
127
+
121
128
  if initialiser
122
129
  if initialiser.is_a? Hash
123
130
  @__jason_state = :new
@@ -175,11 +182,45 @@ module Medea
175
182
  #no changes? no save!
176
183
  return if @__jason_state == :stale or @__jason_state == :ghost
177
184
 
185
+ #validations
186
+ if self.class.owned
187
+ #the parent object needs to be defined!
188
+ raise "#{self.class.name} cannot be saved without setting a parent and list!" unless self.jason_parent && self.jason_parent_list
189
+ end
190
+
178
191
  persist_changes :post
179
192
  end
180
193
 
181
- def to_url
182
- "#{JasonDB::db_auth_url}#{self.class.name}/#{self.jason_key}"
194
+ def add_public *args
195
+ args.reject! do |i|
196
+ not HTTP_VERBS.include? i
197
+ end
198
+ @public += args
199
+ @public.uniq!
200
+ end
201
+
202
+ def remove_public *args
203
+ args.reject! do |i|
204
+ not HTTP_VERBS.include? i
205
+ end
206
+ @public -= args
207
+ @public.uniq!
208
+ end
209
+
210
+ def set_public *args
211
+ args.reject! do |i|
212
+ not HTTP_VERBS.include? i
213
+ end
214
+ @public = args
215
+ @public.uniq!
216
+ end
217
+
218
+ def to_url mode=:secure
219
+ "#{JasonDB::db_auth_url mode}#{self.class.name}/#{self.jason_key}"
220
+ end
221
+
222
+ def to_public_url
223
+ to_url :public
183
224
  end
184
225
 
185
226
  def persist_changes method = :post
@@ -194,14 +235,24 @@ module Medea
194
235
  }
195
236
  post_headers["IF-MATCH"] = @__jason_etag if @__jason_state == :dirty
196
237
 
197
- if self.class.owned
198
- #the parent object needs to be defined!
199
- raise "#{self.class.name} cannot be saved without setting a parent and list!" unless self.jason_parent && self.jason_parent_list
200
- end
201
-
202
238
  post_headers["X-PARENT"] = self.jason_parent.jason_key if self.jason_parent
203
239
  post_headers["X-LIST"] = self.jason_parent_list if self.jason_parent_list
204
240
 
241
+ if opts[:located]
242
+ #set the location headers
243
+ if geohash?
244
+ post_headers["X-GEOHASH"] = geohash
245
+ end
246
+ if latitude? && longitude?
247
+ post_headers["X-LATITUDE"] = latitude
248
+ post_headers["X-LONGITUDE"] = longitude
249
+ end
250
+ end
251
+
252
+ if @public.any?
253
+ post_headers["X-PUBLIC"] = @public.join(",")
254
+ end
255
+
205
256
  url = to_url()
206
257
 
207
258
  #puts "Saving to #{url}"
@@ -227,5 +278,14 @@ module Medea
227
278
  end
228
279
 
229
280
  #end object persistence
281
+
282
+ private
283
+ def opts
284
+ if self.class.class_variable_defined? :@@opts
285
+ self.class.class_variable_get :@@opts
286
+ else
287
+ {}
288
+ end
289
+ end
230
290
  end
231
291
  end
@@ -4,11 +4,18 @@ module JasonObjectMetaProperties
4
4
  end
5
5
 
6
6
  module MetaProperties
7
+ def _class_options &block
8
+ self.send(:class_variable_set, :@@opts, {}) unless self.send(:class_variable_defined?, :@@opts)
9
+ opts = self.send(:class_variable_get, :@@opts)
10
+ yield opts
11
+ self.send(:class_variable_set, :@@opts, opts)
12
+ end
13
+
7
14
  def create_member_list list_name, list_class, list_type
8
- list = {}
9
- list = self.send(:class_variable_get, :@@lists) if self.class_variable_defined? :@@lists
10
- list[list_name] = [list_class, list_type]
11
- self.send(:class_variable_set, "@@lists", list)
15
+ _class_options do |o|
16
+ o[:lists] ||= {}
17
+ o[:lists][list_name] = [list_class, list_type]
18
+ end
12
19
 
13
20
  define_method(list_name) do
14
21
  #puts "Looking at the #{list_name.to_s} list, which is full of #{list_type.name}s"
@@ -29,16 +36,40 @@ module JasonObjectMetaProperties
29
36
  end
30
37
 
31
38
  def has_attachment attachment_name
32
- attachments = []
33
- attachments = self.send(:class_variable_get, :@@attachments) if self.class_variable_defined? :@@attachments
34
- attachments << attachment_name
35
- attachments.uniq!
36
- self.send(:class_variable_set, "@@attachments", attachments)
39
+ _class_options do |o|
40
+ o[:attachments] ||= []
41
+ o[:attachments] << attachment_name
42
+ o[:attachments].uniq!
43
+ end
44
+ end
45
+
46
+ def has_location
47
+ _class_options do |o|
48
+ o[:located] = true
49
+ end
50
+ end
51
+
52
+ #sets the default public/private status for objects in this class
53
+ def public *args
54
+ verbs = [:GET, :POST, :PUT, :DELETE]
55
+ args.reject! do |i|
56
+ not verbs.include? i
57
+ end
58
+ _class_options do |o|
59
+ o[:public] ||= []
60
+ o[:public] << args
61
+ o[:public].flatten!
62
+ o[:public].uniq!
63
+ end
37
64
  end
38
65
 
39
66
  def key_field field_name
40
67
  #this field must be present to save, and it must be unique
41
- self.send(:class_variable_set, :@@key_field, field_name)
68
+ _class_options do |o|
69
+ o[:key_fields] ||= []
70
+ o[:key_fields] << field_name
71
+ o[:key_fields].uniq!
72
+ end
42
73
  end
43
74
  end
44
75
  end
@@ -1,5 +1,5 @@
1
1
  module Medea
2
- VERSION = "0.6.6"
2
+ VERSION = "0.6.7"
3
3
 
4
4
  #When the templates are changed, this version should be incremented
5
5
  #This version is used when uploading/updating the templates
@@ -1,3 +1,4 @@
1
+
1
2
  # -*- encoding: utf-8 -*-
2
3
  $:.push File.expand_path("../lib", __FILE__)
3
4
  require "medea/version"
@@ -20,6 +21,7 @@ Gem::Specification.new do |s|
20
21
  s.add_dependency "json"
21
22
  s.add_dependency "rest-client"
22
23
  s.add_dependency "uuidtools"
24
+ s.add_dependency "pr_geohash"
23
25
 
24
26
  s.add_development_dependency "rspec"
25
27
  end
@@ -92,4 +92,49 @@ describe "JasonObject" do
92
92
  user2.jason_timestamp.should_not be_nil
93
93
  user2.jason_timestamp.should be > t
94
94
  end
95
+
96
+ it "should post location information properly" do
97
+ @user.geohash = "r1r0rshvpuxg"
98
+ RestClient.should_receive(:post).with(anything(), anything(), hash_including("X-GEOHASH" => "r1r0rshvpuxg")).and_return(DummyResponse.new)
99
+ @user.save!
100
+ @user.latitude, @user.longitude = [-37.901949, 145.180206]
101
+ RestClient.should_receive(:post).with(anything(), anything(), hash_including("X-LATITUDE" => -37.901949,
102
+ "X-LONGITUDE" => 145.180206)).and_return(DummyResponse.new)
103
+ @user.save!
104
+ end
105
+
106
+ it "should load location information properly" do
107
+ @user.geohash = "r1r0rshvpuxg"
108
+ @user.latitude, @user.longitude = [-37.901949, 145.180206]
109
+ @user.save!
110
+ retrieved_user = User.get_by_key(@user.jason_key)
111
+ retrieved_user.geohash.should eq(@user.geohash)
112
+ retrieved_user.latitude.should eq(@user.latitude)
113
+ retrieved_user.longitude.should eq(@user.longitude)
114
+ end
115
+
116
+ it "should provide it's public (insecure) url" do
117
+ #should return url non-https, and with no user/password
118
+ (@user.to_url :public).should match(/http:\/\/rest.jasondb.com/)
119
+ @user.to_public_url.should eq(@user.to_url :public)
120
+ end
121
+
122
+ it "should post security information properly" do
123
+ @user.add_public :GET, :POST
124
+ RestClient.should_receive(:post).with(anything(), anything(), hash_including("X-PUBLIC" => "GET,POST")).and_return(DummyResponse.new)
125
+ @user.save!
126
+ end
127
+
128
+ it "should only post valid verbs" do
129
+ @user.add_public :GET, :FAKEVERB
130
+ RestClient.should_receive(:post).with(anything(), anything(), hash_including("X-PUBLIC" => "GET")).and_return(DummyResponse.new)
131
+ @user.save!
132
+ end
133
+
134
+ it "should load security information properly" do
135
+ @user.set_public :GET, :POST
136
+ @user.save!
137
+ retrieved_user = User.get_by_key @user.jason_key
138
+ (retrieved_user.send(:instance_variable_get, :@public)).should eq(["GET", "POST"])
139
+ end
95
140
  end
@@ -7,13 +7,21 @@ class Message < Medea::JasonObject
7
7
  end
8
8
 
9
9
  class User < Medea::JasonObject
10
+ has_location
10
11
  has_many :followees, User
11
12
  owns_many :messages, Message
12
13
  end
13
14
 
14
- #mock the db url
15
- module JasonDB
16
- def JasonDB::db_auth_url mode=:secure
17
- "https://michael:password@rest.jasondb.com/medea-test/"
15
+ class DummyResponse
16
+ def code
17
+ 201
18
18
  end
19
- end
19
+ def headers
20
+ {:Etag => "sometag",
21
+ :timestamp => "12345678"}
22
+ end
23
+ end
24
+
25
+ ENV["jason_user"] = "michael"
26
+ ENV["jason_topic"] = "medea-test"
27
+ ENV["jason_password"] = "password"
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: medea
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 6
8
- - 6
9
- version: 0.6.6
4
+ prerelease:
5
+ version: 0.6.7
10
6
  platform: ruby
11
7
  authors:
12
8
  - Michael Jensen
@@ -14,7 +10,7 @@ autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
12
 
17
- date: 2011-02-03 00:00:00 +11:00
13
+ date: 2011-02-07 00:00:00 +11:00
18
14
  default_executable:
19
15
  dependencies:
20
16
  - !ruby/object:Gem::Dependency
@@ -25,8 +21,6 @@ dependencies:
25
21
  requirements:
26
22
  - - ">="
27
23
  - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
24
  version: "0"
31
25
  type: :runtime
32
26
  version_requirements: *id001
@@ -38,8 +32,6 @@ dependencies:
38
32
  requirements:
39
33
  - - ">="
40
34
  - !ruby/object:Gem::Version
41
- segments:
42
- - 0
43
35
  version: "0"
44
36
  type: :runtime
45
37
  version_requirements: *id002
@@ -51,24 +43,31 @@ dependencies:
51
43
  requirements:
52
44
  - - ">="
53
45
  - !ruby/object:Gem::Version
54
- segments:
55
- - 0
56
46
  version: "0"
57
47
  type: :runtime
58
48
  version_requirements: *id003
59
49
  - !ruby/object:Gem::Dependency
60
- name: rspec
50
+ name: pr_geohash
61
51
  prerelease: false
62
52
  requirement: &id004 !ruby/object:Gem::Requirement
63
53
  none: false
64
54
  requirements:
65
55
  - - ">="
66
56
  - !ruby/object:Gem::Version
67
- segments:
68
- - 0
69
57
  version: "0"
70
- type: :development
58
+ type: :runtime
71
59
  version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: rspec
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ type: :development
70
+ version_requirements: *id005
72
71
  description: Simple wrapper for persisting objects to JasonDB
73
72
  email:
74
73
  - michaelj@jasondb.com
@@ -122,21 +121,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
121
  requirements:
123
122
  - - ">="
124
123
  - !ruby/object:Gem::Version
125
- segments:
126
- - 0
127
124
  version: "0"
128
125
  required_rubygems_version: !ruby/object:Gem::Requirement
129
126
  none: false
130
127
  requirements:
131
128
  - - ">="
132
129
  - !ruby/object:Gem::Version
133
- segments:
134
- - 0
135
130
  version: "0"
136
131
  requirements: []
137
132
 
138
133
  rubyforge_project:
139
- rubygems_version: 1.3.7
134
+ rubygems_version: 1.5.0
140
135
  signing_key:
141
136
  specification_version: 3
142
137
  summary: Simple wrapper for persisting objects to JasonDB