storage_room 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/README.rdoc +10 -4
- data/Rakefile +3 -1
- data/TODO +7 -2
- data/VERSION +1 -1
- data/examples/authentication.rb +5 -3
- data/examples/create_entry.rb +8 -5
- data/examples/destroy_entry.rb +2 -2
- data/examples/get_collections.rb +2 -2
- data/examples/import_csv.rb +4 -4
- data/examples/search_entries.rb +2 -2
- data/examples/update_entry.rb +2 -2
- data/lib/console.rb +12 -0
- data/lib/storage_room.rb +73 -34
- data/lib/storage_room/accessors.rb +190 -0
- data/lib/storage_room/array.rb +3 -23
- data/lib/storage_room/embedded.rb +1 -1
- data/lib/storage_room/embeddeds/field.rb +28 -0
- data/lib/storage_room/embeddeds/fields/association_field.rb +17 -0
- data/lib/storage_room/embeddeds/fields/associations/many_association_field.rb +9 -0
- data/lib/storage_room/embeddeds/fields/associations/one_association_field.rb +9 -0
- data/lib/storage_room/embeddeds/fields/atomic/boolean_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/atomic/date_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/atomic/float_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/atomic/integer_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/atomic/string_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/atomic/time_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/atomic_field.rb +15 -0
- data/lib/storage_room/embeddeds/fields/compound/attachment_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/compound/file_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/compound/image_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/compound/location_field.rb +6 -0
- data/lib/storage_room/embeddeds/fields/compound_field.rb +10 -0
- data/lib/storage_room/embeddeds/file.rb +1 -1
- data/lib/storage_room/embeddeds/image.rb +6 -0
- data/lib/storage_room/embeddeds/location.rb +2 -1
- data/lib/storage_room/extensions/const_defined.rb +12 -0
- data/lib/storage_room/identity_map.rb +117 -0
- data/lib/storage_room/model.rb +19 -23
- data/lib/storage_room/models/collection.rb +76 -11
- data/lib/storage_room/models/entry.rb +6 -32
- data/lib/storage_room/plugins.rb +22 -0
- data/lib/storage_room/proxy.rb +49 -0
- data/lib/storage_room/{base.rb → resource.rb} +13 -36
- data/spec/fixtures/collection.json +0 -16
- data/spec/spec_helper.rb +1 -0
- data/spec/storage_room/accessors_spec.rb +107 -0
- data/spec/storage_room/array_spec.rb +13 -9
- data/spec/storage_room/embedded_spec.rb +5 -1
- data/spec/storage_room/embeddeds/field_spec.rb +25 -0
- data/spec/storage_room/embeddeds/fields/association_field_spec.rb +29 -0
- data/spec/storage_room/embeddeds/fields/associations/many_association_field_spec.rb +21 -0
- data/spec/storage_room/embeddeds/fields/associations/one_association_field_spec.rb +19 -0
- data/spec/storage_room/embeddeds/fields/atomic/boolean_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/atomic/date_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/atomic/float_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/atomic/integer_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/atomic/string_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/atomic/time_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/atomic_field_spec.rb +27 -0
- data/spec/storage_room/embeddeds/fields/compound/attachment_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/compound/file_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/compound/image_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/compound/location_field_spec.rb +5 -0
- data/spec/storage_room/embeddeds/fields/compound_field_spec.rb +17 -0
- data/spec/storage_room/embeddeds/location_spec.rb +13 -1
- data/spec/storage_room/identity_map_spec.rb +53 -0
- data/spec/storage_room/model_spec.rb +70 -50
- data/spec/storage_room/models/collection_spec.rb +57 -14
- data/spec/storage_room/models/entry_spec.rb +16 -20
- data/spec/storage_room/proxy_spec.rb +58 -0
- data/spec/storage_room/resource_spec.rb +98 -0
- data/spec/storage_room_spec.rb +45 -9
- data/storage_room.gemspec +48 -9
- data/tasks/storage_room.rake +3 -0
- metadata +49 -10
- data/lib/storage_room/attributes.rb +0 -46
- data/lib/storage_room/field.rb +0 -8
- data/spec/storage_room/attributes_spec.rb +0 -82
- data/spec/storage_room/base_spec.rb +0 -118
- data/spec/storage_room/field_spec.rb +0 -5
data/lib/storage_room/array.rb
CHANGED
@@ -1,28 +1,8 @@
|
|
1
1
|
module StorageRoom
|
2
2
|
# A container object that contains many models (collections or entries)
|
3
|
-
class Array <
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(attributes = {})
|
8
|
-
self.resources = []
|
9
|
-
super
|
10
|
-
end
|
11
|
-
|
12
|
-
# Set the array with the attributes from the API
|
13
|
-
def set_from_api(attributes)
|
14
|
-
super(attributes)
|
15
|
-
|
16
|
-
self.resources = attributes['resources'].map{|item| self.class.create_from_api(item)} # transform hashes to real objects
|
17
|
-
attributes.delete('resources')
|
18
|
-
end
|
19
|
-
|
20
|
-
# Reset the Array to its default state with all attributes unset
|
21
|
-
def reset!
|
22
|
-
super
|
23
|
-
@resources = []
|
24
|
-
end
|
25
|
-
|
3
|
+
class Array < Resource
|
4
|
+
many :resources
|
5
|
+
|
26
6
|
# Replaces the objects content with the next page of the array if a next page exists
|
27
7
|
def load_next_page!
|
28
8
|
if self[:@next_page_url].present?
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module StorageRoom
|
2
|
+
|
3
|
+
class Field < Embedded
|
4
|
+
key :name
|
5
|
+
key :identifier
|
6
|
+
|
7
|
+
key :hint
|
8
|
+
|
9
|
+
key :input_type
|
10
|
+
|
11
|
+
key :required
|
12
|
+
key :unique
|
13
|
+
|
14
|
+
key :maximum_length
|
15
|
+
key :minimum_length
|
16
|
+
|
17
|
+
key :minimum_number
|
18
|
+
key :maximum_number
|
19
|
+
|
20
|
+
key :minimum_size
|
21
|
+
key :maximum_size
|
22
|
+
|
23
|
+
def add_to_entry_class(klass) # :nodoc:
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module StorageRoom
|
2
|
+
|
3
|
+
class AssociationField < Field
|
4
|
+
key :collection_url
|
5
|
+
|
6
|
+
def add_to_entry_class(klass) # :nodoc:
|
7
|
+
super
|
8
|
+
|
9
|
+
collection
|
10
|
+
end
|
11
|
+
|
12
|
+
# The target collection of the association field
|
13
|
+
def collection
|
14
|
+
@collection ||= Collection.load(self.collection_url)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ConstDefinedExtension
|
2
|
+
def is_constant_defined?(const)
|
3
|
+
if ::RUBY_VERSION =~ /1.9/
|
4
|
+
const_defined?(const, false)
|
5
|
+
else
|
6
|
+
const_defined?(const)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Object.send(:include, ConstDefinedExtension)
|
12
|
+
Module.send(:include, ConstDefinedExtension)
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module StorageRoom
|
2
|
+
# With inspiration from John Nunemaker's MongoMapper
|
3
|
+
module IdentityMap
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
IdentityMap.models << self
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.models
|
11
|
+
@models ||= Set.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.clear
|
15
|
+
models.each { |m| m.identity_map.clear }
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def inherited(descendant)
|
20
|
+
descendant.identity_map = identity_map
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
# Load an object from the identity map if the key (URL) exists
|
25
|
+
def load(url, parameters = {})
|
26
|
+
return nil if url.nil?
|
27
|
+
|
28
|
+
if identity_map_on? && object = identity_map[url]
|
29
|
+
StorageRoom.log("Loaded #{object} from identity map (load)")
|
30
|
+
object
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Load an object from the identity map or create it
|
37
|
+
def new_from_response_data(response_data)
|
38
|
+
url = response_data['@url'] || response_data['url']
|
39
|
+
object = url ? identity_map[url] : nil
|
40
|
+
|
41
|
+
if object.present? && identity_map_on?
|
42
|
+
StorageRoom.log("Loaded #{object} from identity map (new_from_response_data)")
|
43
|
+
object.set_from_response_data(response_data)
|
44
|
+
else
|
45
|
+
object = super
|
46
|
+
if identity_map_on? && url.present? && object.is_a?(Model)
|
47
|
+
identity_map[url] = object
|
48
|
+
StorageRoom.log("Storing #{url} in identity map: #{object}")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
object
|
53
|
+
end
|
54
|
+
|
55
|
+
def identity_map
|
56
|
+
@identity_map ||= {}
|
57
|
+
end
|
58
|
+
|
59
|
+
def identity_map=(v)
|
60
|
+
@identity_map = v
|
61
|
+
end
|
62
|
+
|
63
|
+
def identity_map_status
|
64
|
+
defined?(@identity_map_status) ? @identity_map_status : true
|
65
|
+
end
|
66
|
+
|
67
|
+
def identity_map_on
|
68
|
+
@identity_map_status = true
|
69
|
+
end
|
70
|
+
|
71
|
+
def identity_map_off
|
72
|
+
@identity_map_status = false
|
73
|
+
end
|
74
|
+
|
75
|
+
def identity_map_on?
|
76
|
+
identity_map_status
|
77
|
+
end
|
78
|
+
|
79
|
+
def identity_map_off?
|
80
|
+
!identity_map_on?
|
81
|
+
end
|
82
|
+
|
83
|
+
def without_identity_map(&block)
|
84
|
+
identity_map_off
|
85
|
+
yield
|
86
|
+
ensure
|
87
|
+
identity_map_on
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
module InstanceMethods
|
93
|
+
def identity_map
|
94
|
+
self.class.identity_map
|
95
|
+
end
|
96
|
+
|
97
|
+
def in_identity_map?
|
98
|
+
return false if self[:@url].blank?
|
99
|
+
identity_map.include?(self[:@url])
|
100
|
+
end
|
101
|
+
|
102
|
+
def create(*args)
|
103
|
+
if result = super
|
104
|
+
identity_map[self[:@url]] = self if self.class.identity_map_on?
|
105
|
+
end
|
106
|
+
result
|
107
|
+
end
|
108
|
+
|
109
|
+
def destroy
|
110
|
+
identity_map.delete(self[:@url]) if self.class.identity_map_on?
|
111
|
+
super
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
data/lib/storage_room/model.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module StorageRoom
|
2
2
|
# Abstract superclass for classes that can persist to the remote servers
|
3
|
-
class Model <
|
3
|
+
class Model < Resource
|
4
4
|
class << self
|
5
5
|
# Create a new model with the passed attributes
|
6
6
|
def create(attributes={})
|
@@ -35,31 +35,21 @@ module StorageRoom
|
|
35
35
|
|
36
36
|
# Create a new model and set its attributes
|
37
37
|
def initialize(attributes={})
|
38
|
-
@new_record = true
|
39
38
|
@errors = []
|
40
39
|
|
41
40
|
super
|
42
41
|
end
|
43
|
-
|
44
|
-
# Set the attributes of the model from the API
|
45
|
-
def set_from_api(attributes)
|
46
|
-
super
|
47
|
-
@new_record = false
|
48
|
-
|
49
|
-
self.attributes
|
50
|
-
end
|
51
|
-
|
42
|
+
|
52
43
|
# Reset the model to its default state
|
53
44
|
def reset!
|
54
45
|
super
|
55
|
-
@new_record = true
|
56
46
|
@errors = []
|
57
47
|
true
|
58
48
|
end
|
59
49
|
|
60
50
|
# Has this model been saved to the API already?
|
61
51
|
def new_record?
|
62
|
-
@
|
52
|
+
self['@version'] ? false : true
|
63
53
|
end
|
64
54
|
|
65
55
|
# Create a new model or update an existing model on the server
|
@@ -77,7 +67,7 @@ module StorageRoom
|
|
77
67
|
# Update an existing model on the server
|
78
68
|
def update
|
79
69
|
return false if new_record?
|
80
|
-
httparty = self.class.put(url, :body => to_json)
|
70
|
+
httparty = self.class.put(self[:@url], :body => to_json)
|
81
71
|
handle_save_response(httparty)
|
82
72
|
end
|
83
73
|
|
@@ -85,7 +75,7 @@ module StorageRoom
|
|
85
75
|
def destroy
|
86
76
|
return false if new_record?
|
87
77
|
|
88
|
-
httparty = self.class.delete(url)
|
78
|
+
httparty = self.class.delete(self[:@url])
|
89
79
|
self.class.handle_critical_response_errors(httparty)
|
90
80
|
|
91
81
|
true
|
@@ -96,8 +86,17 @@ module StorageRoom
|
|
96
86
|
self.errors.empty?
|
97
87
|
end
|
98
88
|
|
99
|
-
|
100
|
-
|
89
|
+
# ActiveSupport caused problems when using as_json, so using to_hash
|
90
|
+
def to_hash(args = {}) # :nodoc:
|
91
|
+
args ||= {}
|
92
|
+
|
93
|
+
if args[:nested]
|
94
|
+
{'url' => self[:@url] || self[:url]}
|
95
|
+
else
|
96
|
+
hash = super
|
97
|
+
hash.merge!('@version' => self['@version']) unless new_record?
|
98
|
+
{self.class.json_name => hash}
|
99
|
+
end
|
101
100
|
end
|
102
101
|
|
103
102
|
# The validation errors that were returned by the server
|
@@ -105,22 +104,19 @@ module StorageRoom
|
|
105
104
|
@errors ||= []
|
106
105
|
end
|
107
106
|
|
108
|
-
|
109
|
-
# = Private Methods =
|
110
|
-
# ===================
|
111
|
-
|
112
|
-
private
|
107
|
+
protected
|
113
108
|
def handle_save_response(httparty) # :nodoc:
|
114
109
|
self.class.handle_critical_response_errors(httparty)
|
115
110
|
|
116
111
|
if httparty.response.code == '200' || httparty.response.code == '201'
|
117
|
-
self.
|
112
|
+
self.set_from_response_data(httparty.parsed_response.first[1])
|
118
113
|
true
|
119
114
|
else
|
120
115
|
@errors = httparty.parsed_response['error']['message']
|
121
116
|
false
|
122
117
|
end
|
123
118
|
end
|
119
|
+
|
124
120
|
|
125
121
|
end
|
126
122
|
end
|