medea 0.5.4 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|