medea 0.5.4 → 0.6.0
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/.rvmrc +32 -0
- data/lib/medea.rb +2 -0
- data/lib/medea/jason_base.rb +134 -0
- data/lib/medea/jason_blob.rb +110 -0
- data/lib/medea/jasonobject.rb +38 -136
- data/lib/medea/meta_properties.rb +8 -0
- data/lib/medea/version.rb +1 -1
- data/spec/jason_blob_spec.rb +31 -0
- data/spec/test.jpg +0 -0
- metadata +9 -4
data/.rvmrc
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# adapted from: http://rvm.beginrescueend.com/workflow/rvmrc/
|
4
|
+
|
5
|
+
ruby_string="1.9.2"
|
6
|
+
gemset_name="medea"
|
7
|
+
|
8
|
+
if rvm list strings | grep -q "${ruby_string}" ; then
|
9
|
+
|
10
|
+
# Load or create the specified environment
|
11
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
12
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/${ruby_string}@${gemset_name}" ]] ; then
|
13
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/${ruby_string}@${gemset_name}"
|
14
|
+
else
|
15
|
+
rvm --create "${ruby_string}@${gemset_name}"
|
16
|
+
fi
|
17
|
+
|
18
|
+
else
|
19
|
+
|
20
|
+
# Notify the user to install the desired interpreter before proceeding.
|
21
|
+
echo "${ruby_string} was not found, please run 'rvm install ${ruby_string}' and then cd back into the project directory."
|
22
|
+
|
23
|
+
fi
|
24
|
+
|
25
|
+
#turn on the prompt in PS1
|
26
|
+
#RVM prompt
|
27
|
+
if [ -z "$RVM_PROMPT" ]
|
28
|
+
then
|
29
|
+
RVM_PROMPT=true
|
30
|
+
PS1="[\$(/usr/local/bin/rvm-prompt v g)] $PS1"
|
31
|
+
fi
|
32
|
+
|
data/lib/medea.rb
CHANGED
@@ -5,6 +5,8 @@ module Medea
|
|
5
5
|
require 'medea/inheritable_attributes'
|
6
6
|
require 'medea/active_model_methods'
|
7
7
|
require 'medea/meta_properties'
|
8
|
+
require 'medea/jason_base'
|
9
|
+
require 'medea/jason_blob'
|
8
10
|
require 'medea/jasonobject'
|
9
11
|
require 'medea/jasondeferredquery'
|
10
12
|
require 'medea/jasonlistproperty'
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module Medea
|
2
|
+
class JasonBase
|
3
|
+
#meta-programming interface for lists
|
4
|
+
include ClassLevelInheritableAttributes
|
5
|
+
inheritable_attributes :owned
|
6
|
+
@owned = false
|
7
|
+
|
8
|
+
|
9
|
+
#returns the JasonObject by directly querying the URL
|
10
|
+
#if mode is :lazy, we return a GHOST, if mode is :eager, we return a STALE JasonObject
|
11
|
+
def self.get_by_key(key, mode=:eager)
|
12
|
+
return self.new key, mode
|
13
|
+
end
|
14
|
+
|
15
|
+
#the resolve method takes a key and returns the JasonObject that has that key
|
16
|
+
#This is useful when you have the key, but not the class
|
17
|
+
def self.resolve(key, mode=:lazy)
|
18
|
+
q = JasonDeferredQuery.new :filters => {:VERSION0 => nil, :FILTER => {:HTTP_X_KEY => key, :HTTP_X_ACTION => :POST}}
|
19
|
+
q.filters[:FILTER] ||= {}
|
20
|
+
q.filters[:FILTER][:HTTP_X_KEY] = key
|
21
|
+
resp = JSON.parse(RestClient.get(q.to_url))
|
22
|
+
if resp.has_key? "1"
|
23
|
+
#this is the object, figure out its class
|
24
|
+
resp["1"]["POST_TO"] =~ /([^\/]+)\/#{key}/
|
25
|
+
begin
|
26
|
+
result = Kernel.const_get($1).get_by_key key, :lazy
|
27
|
+
if result["1"].has_key? "CONTENT"
|
28
|
+
result.instance_variable_set(:@__jason_data, result["1"]["CONTENT"])
|
29
|
+
result.instance_variable_set(:@__jason_state, :stale)
|
30
|
+
end
|
31
|
+
if mode == :eager
|
32
|
+
result.send(:load)
|
33
|
+
end
|
34
|
+
rescue
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def ==(other)
|
41
|
+
return false if not other.is_a? JasonBase
|
42
|
+
jason_key == other.jason_key
|
43
|
+
end
|
44
|
+
|
45
|
+
def jason_key
|
46
|
+
#Generate a random UUID for this object.
|
47
|
+
#since jason urls must start with a letter, we'll use the first letter of the class name
|
48
|
+
@__id ||= "#{self.class.name[0].chr.downcase}#{UUIDTools::UUID::random_create.to_s}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def jason_state
|
52
|
+
@__jason_state
|
53
|
+
end
|
54
|
+
|
55
|
+
def jason_etag
|
56
|
+
@__jason_etag ||= ""
|
57
|
+
end
|
58
|
+
|
59
|
+
def jason_parent
|
60
|
+
@__jason_parent ||= nil
|
61
|
+
if @__jason_parent == nil && @__jason_parent_key
|
62
|
+
#key is set but parent not? load the parent
|
63
|
+
@__jason_parent = JasonObject.resolve @__jason_parent_key
|
64
|
+
end
|
65
|
+
@__jason_parent
|
66
|
+
end
|
67
|
+
|
68
|
+
def jason_parent= parent
|
69
|
+
@__jason_parent = parent
|
70
|
+
@__jason_parent_key = parent.jason_key
|
71
|
+
end
|
72
|
+
|
73
|
+
def jason_parent_key
|
74
|
+
@__jason_parent_key ||= nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def jason_parent_key= value
|
78
|
+
@__jason_parent_key = value
|
79
|
+
#reset the parent here?
|
80
|
+
@__jason_parent = nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def jason_parent_list
|
84
|
+
@__jason_parent_list ||= nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def jason_parent_list= value
|
88
|
+
@__jason_parent_list = value
|
89
|
+
end
|
90
|
+
|
91
|
+
def delete! cascade=false
|
92
|
+
#TODO: Put this into some kind of async method or have JasonDB able to set flags on many records at once
|
93
|
+
#This will be REALLY REALLY slowww!
|
94
|
+
if cascade && (self.class.class_variable_defined? :@@lists)
|
95
|
+
@@lists.keys.each do |list_name|
|
96
|
+
#for each list that I have
|
97
|
+
list = send(list_name)
|
98
|
+
list.each do |item|
|
99
|
+
#remove each item from the list, deleting it if possible
|
100
|
+
list.remove! item, true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
persist_changes :delete
|
105
|
+
end
|
106
|
+
|
107
|
+
def build_url
|
108
|
+
url = "#{JasonDB::db_auth_url}@0.content?"
|
109
|
+
params = [
|
110
|
+
"VERSION0",
|
111
|
+
"FILTER=HTTP_X_KEY:#{self.jason_key}",
|
112
|
+
"FILTER=HTTP_X_CLASS:#{self.class.name}"
|
113
|
+
]
|
114
|
+
|
115
|
+
url << params.join("&")
|
116
|
+
url
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
#fetches the data from the JasonDB
|
121
|
+
def load_from_jasondb
|
122
|
+
#because this object might be owned by another, we need to search by key.
|
123
|
+
#not passing a format to the query is a shortcut to getting just the object.
|
124
|
+
url = build_url()
|
125
|
+
|
126
|
+
response = RestClient.get url
|
127
|
+
@__jason_data = JSON.parse response
|
128
|
+
@__jason_etag = response.headers[:etag]
|
129
|
+
@__jason_state = :stale
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Medea
|
2
|
+
class JasonBlob < JasonBase
|
3
|
+
attr_accessor :parent, :attachment_name
|
4
|
+
|
5
|
+
def initialize initialiser=nil, mode=:eager
|
6
|
+
if initialiser
|
7
|
+
if initialiser.is_a? Hash
|
8
|
+
@parent = initialiser[:parent]
|
9
|
+
@attachment_name = initialiser[:name]
|
10
|
+
@__jason_state = :ghost
|
11
|
+
if initialiser[:content]
|
12
|
+
self.contents = initialiser[:content]
|
13
|
+
@__jason_state = :new
|
14
|
+
end
|
15
|
+
return
|
16
|
+
end
|
17
|
+
@__id = initialiser
|
18
|
+
if mode == :eager
|
19
|
+
load_from_jasondb
|
20
|
+
else
|
21
|
+
@__jason_state = :ghost
|
22
|
+
end
|
23
|
+
else
|
24
|
+
@__jason_state = :new
|
25
|
+
@__jason_data = nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_url
|
30
|
+
"#{@parent.to_url}/#{@attachment_name}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def load_from_jasondb
|
34
|
+
#because this object might be owned by another, we need to search by key.
|
35
|
+
#not passing a format to the query is a shortcut to getting just the object.
|
36
|
+
url = to_url
|
37
|
+
response = nil
|
38
|
+
begin
|
39
|
+
response = RestClient.get url
|
40
|
+
|
41
|
+
#don't JSON parse blob data!
|
42
|
+
@__jason_data = response
|
43
|
+
@__jason_etag = response.headers[:etag]
|
44
|
+
@__jason_state = :stale
|
45
|
+
rescue
|
46
|
+
#an exception here means a bad url or a 404.
|
47
|
+
#404 simply means no data yet for this attachment
|
48
|
+
@__jason_state = :new
|
49
|
+
@__jason_data = nil
|
50
|
+
return
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def contents
|
55
|
+
load_from_jasondb if @__jason_state == :ghost
|
56
|
+
@__jason_data
|
57
|
+
end
|
58
|
+
|
59
|
+
def contents= data
|
60
|
+
@__jason_data = data
|
61
|
+
@__jason_state = :dirty
|
62
|
+
end
|
63
|
+
|
64
|
+
def set_content_type type=nil
|
65
|
+
if type
|
66
|
+
@content_type = type
|
67
|
+
elsif contents.is_a? IO
|
68
|
+
@content_type = image_type(contents)
|
69
|
+
elsif contents.is_a? String
|
70
|
+
@content_type = "text/plain"
|
71
|
+
else
|
72
|
+
@content_type = "application/octet-stream"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def image_type(file)
|
77
|
+
case IO.read(file, 10)
|
78
|
+
when /^GIF8/; 'image/gif'
|
79
|
+
when /^\x89PNG/; 'image/png'
|
80
|
+
when /^\xff\xd8\xff\xe0\x00\x10JFIF/; 'image/jpeg'
|
81
|
+
when /^\xff\xd8\xff\xe1(.*){2}Exif/; 'image/jpeg'
|
82
|
+
else 'unknown'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def save!
|
87
|
+
return if @__jason_state == :stale or @__jason_state == :ghost
|
88
|
+
set_content_type
|
89
|
+
#write the contents of @__jason_data to parent url/attachment name
|
90
|
+
post_headers = {
|
91
|
+
:content_type => @content_type,
|
92
|
+
:length => contents.size,
|
93
|
+
"X-KEY" => self.jason_key,
|
94
|
+
"X-CLASS" => self.class.name,
|
95
|
+
"X-PARENT" => @parent.jason_key,
|
96
|
+
"X_LIST" => @attachment_name
|
97
|
+
#also want to add the eTag here!
|
98
|
+
#may also want to add any other indexable fields that the user specifies?
|
99
|
+
}
|
100
|
+
|
101
|
+
resp = RestClient.post to_url, contents, post_headers
|
102
|
+
|
103
|
+
if resp.code == 201
|
104
|
+
true
|
105
|
+
else
|
106
|
+
false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/medea/jasonobject.rb
CHANGED
@@ -5,21 +5,15 @@ module Medea
|
|
5
5
|
require 'json'
|
6
6
|
require 'uuidtools'
|
7
7
|
|
8
|
-
class JasonObject
|
8
|
+
class JasonObject < JasonBase
|
9
9
|
|
10
10
|
include Medea::ActiveModelMethods
|
11
11
|
if defined? ActiveModel
|
12
12
|
extend ActiveModel::Naming
|
13
13
|
end
|
14
|
-
#include JasonDB
|
15
|
-
|
16
|
-
#meta-programming interface for lists
|
17
|
-
include ClassLevelInheritableAttributes
|
18
|
-
inheritable_attributes :owned
|
19
|
-
@owned = false
|
20
14
|
|
21
15
|
include JasonObjectMetaProperties
|
22
|
-
|
16
|
+
attr_accessor :attachments
|
23
17
|
#end meta
|
24
18
|
|
25
19
|
#Here we're going to put the "query" interface
|
@@ -30,12 +24,6 @@ module Medea
|
|
30
24
|
JasonDeferredQuery.new :class => self, :filters => {:VERSION0 => nil, :FILTER => {:HTTP_X_CLASS => self, :HTTP_X_ACTION => :POST}}
|
31
25
|
end
|
32
26
|
|
33
|
-
#returns the JasonObject by directly querying the URL
|
34
|
-
#if mode is :lazy, we return a GHOST, if mode is :eager, we return a STALE JasonObject
|
35
|
-
def JasonObject.get_by_key(key, mode=:eager)
|
36
|
-
return self.new key, mode
|
37
|
-
end
|
38
|
-
|
39
27
|
#here we will capture:
|
40
28
|
#members_of(object) (where object is an instance of a class that this class can be a member of)
|
41
29
|
#find_by_<property>(value)
|
@@ -58,38 +46,12 @@ module Medea
|
|
58
46
|
end
|
59
47
|
#end query interface
|
60
48
|
|
61
|
-
#the resolve method takes a key and returns the JasonObject that has that key
|
62
|
-
#This is useful when you have the key, but not the class
|
63
|
-
def JasonObject.resolve(key, mode=:lazy)
|
64
|
-
q = JasonDeferredQuery.new :filters => {:VERSION0 => nil, :FILTER => {:HTTP_X_KEY => key, :HTTP_X_ACTION => :POST}}
|
65
|
-
q.filters[:FILTER] ||= {}
|
66
|
-
q.filters[:FILTER][:HTTP_X_KEY] = key
|
67
|
-
resp = JSON.parse(RestClient.get(q.to_url))
|
68
|
-
if resp.has_key? "1"
|
69
|
-
#this is the object, figure out its class
|
70
|
-
resp["1"]["POST_TO"] =~ /([^\/]+)\/#{key}/
|
71
|
-
begin
|
72
|
-
result = Kernel.const_get($1).get_by_key key, :lazy
|
73
|
-
if result["1"].has_key? "CONTENT"
|
74
|
-
result.instance_variable_set(:@__jason_data, result["1"]["CONTENT"])
|
75
|
-
result.instance_variable_set(:@__jason_state, :stale)
|
76
|
-
end
|
77
|
-
if mode == :eager
|
78
|
-
result.send(:load)
|
79
|
-
end
|
80
|
-
rescue
|
81
|
-
nil
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def ==(other)
|
87
|
-
return false if not other.is_a? JasonObject
|
88
|
-
jason_key == other.jason_key
|
89
|
-
end
|
90
|
-
|
91
49
|
#"flexihash" access interface
|
92
50
|
def []=(key, value)
|
51
|
+
if @attachments.keys.include? key.to_sym
|
52
|
+
@attachments[key.to_sym] = Medea::JasonBlob.new({:parent => self, :name => key, :content => value})
|
53
|
+
return
|
54
|
+
end
|
93
55
|
@__jason_data ||= {}
|
94
56
|
@__jason_state = :dirty if jason_state == :stale
|
95
57
|
|
@@ -97,6 +59,14 @@ module Medea
|
|
97
59
|
end
|
98
60
|
|
99
61
|
def [](key)
|
62
|
+
if @attachments.keys.include? key.to_sym
|
63
|
+
if not @attachments[key.to_sym]
|
64
|
+
#retrieve the JasonBlob for this key
|
65
|
+
@attachments[key.to_sym] = Medea::JasonBlob.new({:parent => self, :name => key})
|
66
|
+
end
|
67
|
+
|
68
|
+
return @attachments[key.to_sym].contents
|
69
|
+
end
|
100
70
|
@__jason_data[key]
|
101
71
|
end
|
102
72
|
|
@@ -104,7 +74,7 @@ module Medea
|
|
104
74
|
# "weak object" that can take any attribute.
|
105
75
|
# Assigning any attribute will add it to the object's hash (and then be POSTed to JasonDB on the next save)
|
106
76
|
def method_missing(name, *args, &block)
|
107
|
-
|
77
|
+
load_from_jasondb if @__jason_state == :ghost
|
108
78
|
field = name.to_s
|
109
79
|
if field =~ /(.*)=$/ # We're assigning
|
110
80
|
self[$1] = args[0]
|
@@ -130,6 +100,13 @@ module Medea
|
|
130
100
|
end
|
131
101
|
|
132
102
|
def initialize initialiser = nil, mode = :eager
|
103
|
+
@attachments = {}
|
104
|
+
if self.class.class_variable_defined? :@@attachments
|
105
|
+
(self.class.class_variable_get :@@attachments).each do |k|
|
106
|
+
@attachments[k] = nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
133
110
|
if initialiser
|
134
111
|
if initialiser.is_a? Hash
|
135
112
|
@__jason_state = :new
|
@@ -137,7 +114,7 @@ module Medea
|
|
137
114
|
else
|
138
115
|
@__id = initialiser
|
139
116
|
if mode == :eager
|
140
|
-
|
117
|
+
load_from_jasondb
|
141
118
|
else
|
142
119
|
@__jason_state = :ghost
|
143
120
|
end
|
@@ -148,54 +125,13 @@ module Medea
|
|
148
125
|
end
|
149
126
|
end
|
150
127
|
|
151
|
-
def jason_key
|
152
|
-
#Generate a random UUID for this object.
|
153
|
-
#since jason urls must start with a letter, we'll use the first letter of the class name
|
154
|
-
@__id ||= "#{self.class.name[0].chr.downcase}#{UUIDTools::UUID::random_create.to_s}"
|
155
|
-
end
|
156
|
-
|
157
128
|
def to_s
|
158
129
|
jason_key
|
159
130
|
end
|
160
131
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
def jason_etag
|
166
|
-
@__jason_etag ||= ""
|
167
|
-
end
|
168
|
-
|
169
|
-
def jason_parent
|
170
|
-
@__jason_parent ||= nil
|
171
|
-
if @__jason_parent == nil && @__jason_parent_key
|
172
|
-
#key is set but parent not? load the parent
|
173
|
-
@__jason_parent = JasonObject.resolve @__jason_parent_key
|
174
|
-
end
|
175
|
-
@__jason_parent
|
176
|
-
end
|
177
|
-
|
178
|
-
def jason_parent= parent
|
179
|
-
@__jason_parent = parent
|
180
|
-
@__jason_parent_key = parent.jason_key
|
181
|
-
end
|
182
|
-
|
183
|
-
def jason_parent_key
|
184
|
-
@__jason_parent_key ||= nil
|
185
|
-
end
|
186
|
-
|
187
|
-
def jason_parent_key= value
|
188
|
-
@__jason_parent_key = value
|
189
|
-
#reset the parent here?
|
190
|
-
@__jason_parent = nil
|
191
|
-
end
|
192
|
-
|
193
|
-
def jason_parent_list
|
194
|
-
@__jason_parent_list ||= nil
|
195
|
-
end
|
196
|
-
|
197
|
-
def jason_parent_list= value
|
198
|
-
@__jason_parent_list = value
|
132
|
+
#converts the data hash (that is, @__jason_data) to JSON format
|
133
|
+
def serialise
|
134
|
+
JSON.generate(@__jason_data)
|
199
135
|
end
|
200
136
|
|
201
137
|
#object persistence methods
|
@@ -217,61 +153,26 @@ module Medea
|
|
217
153
|
return false
|
218
154
|
end
|
219
155
|
end
|
156
|
+
|
220
157
|
def save!
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
persist_changes :post
|
225
|
-
end
|
226
|
-
|
227
|
-
def delete! cascade=false
|
228
|
-
#TODO: Put this into some kind of async method or have JasonDB able to set flags on many records at once
|
229
|
-
#This will be REALLY REALLY slowww!
|
230
|
-
if cascade && (self.class.class_variable_defined? :@@lists)
|
231
|
-
@@lists.keys.each do |list_name|
|
232
|
-
#for each list that I have
|
233
|
-
list = send(list_name)
|
234
|
-
list.each do |item|
|
235
|
-
#remove each item from the list, deleting it if possible
|
236
|
-
list.remove! item, true
|
158
|
+
@attachments.each do |k, v|
|
159
|
+
if v
|
160
|
+
v.save!
|
237
161
|
end
|
238
162
|
end
|
239
|
-
end
|
240
|
-
persist_changes :delete
|
241
|
-
end
|
242
163
|
|
243
|
-
|
164
|
+
#no changes? no save!
|
165
|
+
return if @__jason_state == :stale or @__jason_state == :ghost
|
244
166
|
|
245
|
-
|
246
|
-
def to_json
|
247
|
-
JSON.generate(@__jason_data)
|
167
|
+
persist_changes :post
|
248
168
|
end
|
249
169
|
|
250
|
-
|
251
|
-
|
252
|
-
#fetches the data from the JasonDB
|
253
|
-
def load
|
254
|
-
#because this object might be owned by another, we need to search by key.
|
255
|
-
#not passing a format to the query is a shortcut to getting just the object.
|
256
|
-
url = "#{JasonDB::db_auth_url}@0.content?"
|
257
|
-
params = [
|
258
|
-
"VERSION0",
|
259
|
-
"FILTER=HTTP_X_KEY:#{self.jason_key}",
|
260
|
-
"FILTER=HTTP_X_CLASS:#{self.class.name}"
|
261
|
-
]
|
262
|
-
|
263
|
-
url << params.join("&")
|
264
|
-
#url = "#{JasonDB::db_auth_url}#{self.class.name}/#{self.jason_key}"
|
265
|
-
|
266
|
-
#puts " = Retrieving #{self.class.name} at #{url}"
|
267
|
-
response = RestClient.get url
|
268
|
-
@__jason_data = JSON.parse response
|
269
|
-
@__jason_etag = response.headers[:etag]
|
270
|
-
@__jason_state = :stale
|
170
|
+
def to_url
|
171
|
+
"#{JasonDB::db_auth_url}#{self.class.name}/#{self.jason_key}"
|
271
172
|
end
|
272
173
|
|
273
174
|
def persist_changes method = :post
|
274
|
-
payload = self.
|
175
|
+
payload = self.serialise
|
275
176
|
|
276
177
|
post_headers = {
|
277
178
|
:content_type => 'application/json',
|
@@ -290,7 +191,7 @@ module Medea
|
|
290
191
|
post_headers["X-PARENT"] = self.jason_parent.jason_key if self.jason_parent
|
291
192
|
post_headers["X-LIST"] = self.jason_parent_list if self.jason_parent_list
|
292
193
|
|
293
|
-
url =
|
194
|
+
url = to_url()
|
294
195
|
|
295
196
|
#puts "Saving to #{url}"
|
296
197
|
if method == :post
|
@@ -313,5 +214,6 @@ module Medea
|
|
313
214
|
@__jason_state = :stale
|
314
215
|
end
|
315
216
|
|
217
|
+
#end object persistence
|
316
218
|
end
|
317
219
|
end
|
@@ -28,6 +28,14 @@ module JasonObjectMetaProperties
|
|
28
28
|
list_class.owned = true
|
29
29
|
end
|
30
30
|
|
31
|
+
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)
|
37
|
+
end
|
38
|
+
|
31
39
|
def key_field field_name
|
32
40
|
#this field must be present to save, and it must be unique
|
33
41
|
self.send(:class_variable_set, :@@key_field, field_name)
|
data/lib/medea/version.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Jason Blob" do
|
4
|
+
|
5
|
+
class Update < Medea::JasonObject
|
6
|
+
has_attachment :avatar
|
7
|
+
end
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
@update = Update.new
|
11
|
+
end
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
@update.delete!
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be persisted" do
|
18
|
+
@update.avatar = "Here's some text!"
|
19
|
+
@update.save!
|
20
|
+
u2 = Update.get_by_key(@update.jason_key)
|
21
|
+
u2.avatar.should eq("Here's some text!")
|
22
|
+
u2.avatar.size.should eq("Here's some text!".size)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should work for larger images" do
|
26
|
+
f = File.new("./spec/test.jpg", "r")
|
27
|
+
@update.avatar = f
|
28
|
+
@update.save!
|
29
|
+
Update.get_by_key(@update.jason_key).avatar.size.should eq(f.size)
|
30
|
+
end
|
31
|
+
end
|
data/spec/test.jpg
ADDED
Binary file
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 6
|
8
|
+
- 0
|
9
|
+
version: 0.6.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Michael Jensen
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-01
|
17
|
+
date: 2011-02-01 00:00:00 +11:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -79,6 +79,7 @@ extensions: []
|
|
79
79
|
extra_rdoc_files: []
|
80
80
|
|
81
81
|
files:
|
82
|
+
- .rvmrc
|
82
83
|
- Gemfile
|
83
84
|
- README
|
84
85
|
- Rakefile
|
@@ -88,6 +89,8 @@ files:
|
|
88
89
|
- lib/medea/active_model_methods.rb
|
89
90
|
- lib/medea/dummy_logger.rb
|
90
91
|
- lib/medea/inheritable_attributes.rb
|
92
|
+
- lib/medea/jason_base.rb
|
93
|
+
- lib/medea/jason_blob.rb
|
91
94
|
- lib/medea/jasondb.rb
|
92
95
|
- lib/medea/jasondeferredquery.rb
|
93
96
|
- lib/medea/jasonlistproperty.rb
|
@@ -99,10 +102,12 @@ files:
|
|
99
102
|
- lib/medea/version.rb
|
100
103
|
- medea.gemspec
|
101
104
|
- spec/deferred_query_spec.rb
|
105
|
+
- spec/jason_blob_spec.rb
|
102
106
|
- spec/jason_object_spec.rb
|
103
107
|
- spec/list_properties_spec.rb
|
104
108
|
- spec/medea_spec.rb
|
105
109
|
- spec/spec_helper.rb
|
110
|
+
- spec/test.jpg
|
106
111
|
has_rdoc: true
|
107
112
|
homepage: ""
|
108
113
|
licenses: []
|