restly 0.0.1.beta.2 → 0.0.1.beta.3

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/lib/restly/base.rb CHANGED
@@ -8,6 +8,7 @@ module Restly
8
8
  autoload :Includes
9
9
  autoload :Fields
10
10
  autoload :EmbeddedAssociations
11
+ autoload :PaginationOptions
11
12
 
12
13
  # Thread Local Accessor
13
14
  extend Restly::ThreadLocal
@@ -42,6 +43,9 @@ module Restly
42
43
  include Instance
43
44
  include Fields
44
45
 
46
+ # Pagination Options
47
+ include PaginationOptions
48
+
45
49
  # Set up the Attributes
46
50
  thread_local_accessor :current_token
47
51
  class_attribute :path, instance_writer: false, instance_reader: false
@@ -79,8 +79,7 @@ module Restly::Base::Instance::Attributes
79
79
  def write_attribute(attr, val)
80
80
  if fields.include?(attr)
81
81
  send("#{attr}_will_change!") if val != read_attribute(attr) && loaded?
82
- @attributes[attr.to_sym] = val
83
-
82
+ @attributes[attr.to_sym] = convert_attr_type(val)
84
83
  else
85
84
  ActiveSupport::Notifications.instrument("missing_attribute.restly", attr: attr)
86
85
  end
@@ -90,7 +89,7 @@ module Restly::Base::Instance::Attributes
90
89
  options.reverse_merge!({ autoload: true })
91
90
 
92
91
  # Try and get the attribute if the item is not loaded
93
- if initialized? && attr.to_sym != :id && @attributes[attr].nil? && !!options[:autoload] && !loaded? && exists?
92
+ if initialized? && attr.to_sym != :id && attribute_not_loaded?(attr) && !!options[:autoload] && !loaded? && exists?
94
93
  load!
95
94
  end
96
95
 
@@ -110,4 +109,24 @@ module Restly::Base::Instance::Attributes
110
109
  self.attributes = parsed_response(response)
111
110
  end
112
111
 
112
+ def attribute_loaded?(attr)
113
+ @attributes.has_key? attr
114
+ end
115
+
116
+ def attribute_not_loaded?(attr)
117
+ !attribute_loaded?(attr)
118
+ end
119
+
120
+ def convert_attr_type(val)
121
+ time = (val.to_time rescue nil)
122
+ date = (val.to_date rescue nil)
123
+ if time.try(:iso8601) == val
124
+ time
125
+ elsif date.try(:to_s) == val
126
+ date
127
+ else
128
+ val
129
+ end
130
+ end
131
+
113
132
  end
@@ -25,13 +25,20 @@ module Restly::Base::Instance::Persistence
25
25
  end
26
26
 
27
27
  def reload!
28
- return unless initialized?
28
+ return unless initialized? && loaded?
29
29
  raise Restly::Error::MissingId, "Cannot reload #{resource_name}, either it hasn't been created or it is missing an ID." unless exists?
30
+ @loaded = true
30
31
  set_attributes_from_response connection.get(path_with_format, force: true)
32
+ self
33
+ end
34
+
35
+ def load!
36
+ return unless initialized? && loaded?
37
+ raise Restly::Error::MissingId, "Cannot load #{resource_name}, either it hasn't been created or it is missing an ID." unless exists?
31
38
  @loaded = true
39
+ set_attributes_from_response connection.get(path_with_format)
32
40
  self
33
41
  end
34
42
 
35
- alias :load! :reload!
36
43
 
37
44
  end
@@ -0,0 +1,41 @@
1
+ module Restly::Base::PaginationOptions
2
+ extend ActiveSupport::Concern
3
+
4
+ Collection = Restly::Collection
5
+
6
+ included do
7
+ extend ClassMethods
8
+ class_attribute :pagination_mapping, :pagination_options, instance_writer: false
9
+
10
+ pagination per_page: 25
11
+
12
+ end
13
+
14
+ module ClassMethods
15
+
16
+ delegate :page, to: :empty_collection
17
+
18
+ def pagination(options={})
19
+ # Assert Main Options
20
+ options.assert_valid_keys :per_page, :mapping
21
+
22
+ # Reverse Merge and Assert Mappings
23
+ (options[:mapping] ||= {}).reverse_merge!({ current_page: :page,
24
+ per_page: :per_page,
25
+ total_pages: :total_pages,
26
+ total_entries: :total_entries })
27
+
28
+ options[:mapping].assert_valid_keys :root, :current_page, :per_page, :total_pages, :total_entries
29
+
30
+ # Set the options
31
+ self.pagination_mapping = options.delete(:mapping)
32
+ self.pagination_options = options
33
+ end
34
+
35
+ def empty_collection
36
+ Collection.new(self, [])
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -1,5 +1,7 @@
1
1
  module Restly::Base::Resource::Finders
2
2
 
3
+ Collection = Restly::Collection
4
+
3
5
  def find(id, *args)
4
6
  options = args.extract_options!
5
7
 
@@ -18,7 +20,7 @@ module Restly::Base::Resource::Finders
18
20
 
19
21
  def collection_from_response(response)
20
22
  raise Restly::Error::InvalidResponse unless response.is_a? OAuth2::Response
21
- Restly::Collection.new resource, nil, response: response
23
+ Collection.new resource, nil, response: response
22
24
  end
23
25
 
24
26
  def instance_from_response(response)
@@ -7,6 +7,7 @@ class Restly::Collection < Array
7
7
  include Restly::Base::Resource::BatchActions
8
8
  include Restly::Base::GenericMethods
9
9
  include ErrorHandling
10
+ include Pagination
10
11
 
11
12
  delegate :resource_name, :new, :client, to: :resource
12
13
 
@@ -46,14 +47,6 @@ class Restly::Collection < Array
46
47
 
47
48
  alias :collect :map
48
49
 
49
- #def paginate(opts={})
50
- # @pagination_opts = opts
51
- # collection = self.dup
52
- # collection.extend(Restly::Collection::Pagination)
53
- # return page(opts[:page]) unless opts[:page] == current_page && opts[:per_page] == response_per_page
54
- # collection
55
- #end
56
-
57
50
  def <<(instance)
58
51
  raise Restly::Error::InvalidObject, "Object is not an instance of #{resource}" unless accepts?(instance)
59
52
  super(instance)
@@ -1,36 +1,48 @@
1
1
  module Restly::Collection::Pagination
2
+ extend ActiveSupport::Concern
2
3
 
3
- def page(num)
4
- with_params(page: num, per_page: per_page).all.paginate(page: num, per_page: per_page)
4
+ included do
5
+ delegate :pagination_options, :pagination_mapping, to: :resource
5
6
  end
6
7
 
7
- def current_page
8
- pagination[:current_page] || pagination[:page]
8
+ def paginates?
9
+ !!current_page
9
10
  end
10
11
 
11
- def per_page
12
- @pagination_opts[:per_page] || pagination[:per_page]
12
+ def page(num, options={})
13
+ num = 1 unless (num = num.to_i) > 0
14
+ options.assert_valid_keys(:per_page)
15
+ per_page = (options[:per_page] || pagination_options[:per_page]).to_i
16
+ resource.with_params(page: num, per_page: per_page).all
13
17
  end
14
18
 
15
- def response_per_page
16
- pagination[:per_page]
17
- end
19
+ private
18
20
 
19
- def total_pages
20
- pagination[:total_pages]
21
+ def method_missing(m, *args, &block)
22
+ mapping = pagination_mapping[m]
23
+ if pagination.has_key? mapping
24
+ raise ArgumentError, "doesn't accept arguments" if args.present?
25
+ pagination[mapping].try(:to_i)
26
+ else
27
+ super
28
+ end
21
29
  end
22
30
 
23
- def total_entries
24
- pagination[:total_entries]
31
+ def respond_to_missing?(m, include_private = false)
32
+ mapping = pagination_mapping[m]
33
+ pagination.has_key? mapping
25
34
  end
26
35
 
27
- private
28
-
29
36
  def pagination
30
- parsed = @response.parsed || {}
31
- pagination = parsed[:pagination] || parsed
32
- pagination.select!{ |k,v| /page|current_page|entries|total_entries|per_page|total_pages|total/ =~ k.to_s }
33
- pagination.with_indifferent_access
37
+ return {} unless response.parsed.is_a? Hash
38
+ if (root = pagination_mapping[:root])
39
+ response.parsed[root.to_sym] || response.parsed[root.to_s] || {}
40
+ else
41
+ pagination_keys = pagination_mapping.values.compact.map do |key|
42
+ [key.to_s, key.to_sym]
43
+ end.flatten
44
+ response.parsed.slice(*pagination_keys)
45
+ end.with_indifferent_access
34
46
  end
35
47
 
36
48
  end
@@ -121,7 +121,11 @@ class Restly::Connection < OAuth2::AccessToken
121
121
 
122
122
  cache_log("Restly::CacheExpire", cache_key, :yellow) { Rails.cache.delete(cache_key) } if response.error
123
123
 
124
- raise Restly::Error::ConnectionError, "#{response.status}: #{status_string(response.status)}" if response.status >= 500
124
+ if response.status >= 500
125
+ site = URI.parse(client.site)
126
+ formatted_path = ["#{site.scheme}://#{site.host}", "#{site.port}", path].join
127
+ raise Restly::Error::ConnectionError, "#{response.status}: #{status_string(response.status)}\nurl: #{formatted_path}"
128
+ end
125
129
 
126
130
  # Return the response
127
131
  response
@@ -130,7 +134,7 @@ class Restly::Connection < OAuth2::AccessToken
130
134
 
131
135
  def request_log(name, path, verb, color=:light_green, &block)
132
136
  site = URI.parse(client.site)
133
- formatted_path = ["#{site.scheme}://#{site.host}", path].join("/")
137
+ formatted_path = ["#{site.scheme}://#{site.host}", ":#{site.port}", path].join
134
138
  ActiveSupport::Notifications.instrument("request.restly", url: formatted_path, method: verb, name: name, color: color, &block)
135
139
  end
136
140
 
@@ -1,3 +1,3 @@
1
1
  module Restly
2
- VERSION = "0.0.1.beta.2"
2
+ VERSION = "0.0.1.beta.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.beta.2
4
+ version: 0.0.1.beta.3
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-21 00:00:00.000000000 Z
12
+ date: 2012-11-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: oauth2
@@ -195,6 +195,7 @@ files:
195
195
  - lib/restly/base/instance/error_handling.rb
196
196
  - lib/restly/base/instance/persistence.rb
197
197
  - lib/restly/base/instance/write_callbacks.rb
198
+ - lib/restly/base/pagination_options.rb
198
199
  - lib/restly/base/resource.rb
199
200
  - lib/restly/base/resource/batch_actions.rb
200
201
  - lib/restly/base/resource/finders.rb