storage_room 0.2.1 → 0.3.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/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
|