medea 0.6.6 → 0.6.7

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