rocket_pants 1.2.1 → 1.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/lib/rocket_pants.rb CHANGED
@@ -32,17 +32,21 @@ module RocketPants
32
32
  autoload :JSONP, 'rocket_pants/controller/jsonp'
33
33
  autoload :Rescuable, 'rocket_pants/controller/rescuable'
34
34
  autoload :Respondable, 'rocket_pants/controller/respondable'
35
+ autoload :HeaderMetadata, 'rocket_pants/controller/header_metadata'
36
+ autoload :Linking, 'rocket_pants/controller/linking'
35
37
  autoload :Versioning, 'rocket_pants/controller/versioning'
36
38
  autoload :FormatVerification, 'rocket_pants/controller/format_verification'
37
39
  autoload :UrlFor, 'rocket_pants/controller/url_for'
38
40
 
39
- mattr_accessor :caching_enabled
41
+ mattr_accessor :caching_enabled, :header_metadata
40
42
  self.caching_enabled = false
43
+ self.header_metadata = false
41
44
 
42
45
  mattr_writer :cache
43
46
 
44
47
  class << self
45
48
  alias caching_enabled? caching_enabled
49
+ alias header_metadata? header_metadata
46
50
 
47
51
  def cache
48
52
  @@cache ||= Moneta::Memory.new
@@ -18,6 +18,8 @@ module RocketPants
18
18
  ActionController::HttpAuthentication::Token::ControllerMethods,
19
19
  UrlFor,
20
20
  Respondable,
21
+ HeaderMetadata,
22
+ Linking,
21
23
  Versioning,
22
24
  Instrumentation,
23
25
  Caching,
@@ -2,6 +2,7 @@ module RocketPants
2
2
  class CacheMiddleware
3
3
 
4
4
  NOT_MODIFIED = [304, {}, []]
5
+ DIVIDER = ":"
5
6
 
6
7
  def initialize(app)
7
8
  @app = app
@@ -29,7 +30,6 @@ module RocketPants
29
30
 
30
31
  def has_valid_etag?
31
32
  return false if (etags = request_etags).blank?
32
- debug ""
33
33
  etags.any? do |etag|
34
34
  cache_key, value = extract_cache_key_and_value etag
35
35
  debug "Processing cache key for path #{request_path}"
@@ -39,7 +39,7 @@ module RocketPants
39
39
  end
40
40
 
41
41
  def extract_cache_key_and_value(etag)
42
- etag.to_s.split(":", 2)
42
+ etag.to_s.split(DIVIDER, 2)
43
43
  end
44
44
 
45
45
  def fresh?(key, value)
@@ -48,7 +48,7 @@ module RocketPants
48
48
 
49
49
  def request_etags
50
50
  stored = @env['HTTP_IF_NONE_MATCH']
51
- stored.present? && stored.to_s.scan(/"([^"]+)"/)
51
+ stored.present? && stored.to_s.scan(/"([^"]+)"/).flatten.select { |i| i.include?(DIVIDER) }
52
52
  end
53
53
 
54
54
  def debug(message)
@@ -0,0 +1,38 @@
1
+ module RocketPants
2
+ module HeaderMetadata
3
+
4
+ # Given a hash of request metadata, will:
5
+ # 1. Write out the headers for the current metadata
6
+ # 2. Return the hash, suitable for merging into the response hash
7
+ # 3. Start a dance party.
8
+ #
9
+ # @param [Hash{Symbol => Object}] metadata the hash of the request metadata.
10
+ # @return [Hash{Symbol => Object}] the passed in metadata
11
+ def expose_metadata(metadata)
12
+ metadata_headers { build_header_hash(metadata) }
13
+ super # Call any other versions of the method.
14
+ end
15
+
16
+
17
+ # Given a block which returns a Hash, will call and merge the block iff header metadata
18
+ # is enabled. This is to avoid the overhead of generating headers on every request when
19
+ # it's disabled.
20
+ def metadata_headers(&blk)
21
+ headers.merge! blk.call if RocketPants.header_metadata?
22
+ end
23
+
24
+ def build_header_hash(options, hash = {}, prefix = 'X-Api')
25
+ options.each_pair do |k, v|
26
+ current = "#{prefix}-#{k.to_s.titleize.tr(" ", "-")}"
27
+ if v.is_a?(Hash)
28
+ build_header_hash v, hash, current
29
+ else
30
+ value = Array(v).join(", ")
31
+ hash[current] = value if value.present?
32
+ end
33
+ end
34
+ hash
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ module RocketPants
2
+ module Linking
3
+
4
+ # Generates a Link: header with the specified rel, uri and attributes.
5
+ # @param [String, Symbol] rel the relation of the given link
6
+ # @param [String] uri the full uri to the specified link resource
7
+ # @param [Hash] attributes any other attributes for the link
8
+ def link(rel, uri, attributes = {})
9
+ headers['Link'] ||= []
10
+ attributes = {:rel => rel}.merge(attributes)
11
+ link = "<#{uri}>"
12
+ attributes.each_pair { |k, v| link << "; #{k}=\"#{v}\"" }
13
+ headers['Link'] << link
14
+ end
15
+
16
+ # Lets you add a series of links for the current resource.
17
+ # @param [Hash{Symbol => String}] links a hash of links. Those with nil as the value are skipped.
18
+ def links(links = {})
19
+ links.each_pair do |rel, uri|
20
+ link rel, uri if uri
21
+ end
22
+ end
23
+
24
+ # Hook method - Implement this to link to the current resource and we'll automatically add header links.
25
+ def page_url(page)
26
+ nil
27
+ end
28
+
29
+ def expose_metadata(metadata)
30
+ super.tap do |meta|
31
+ if RocketPants.header_metadata? && (pagination = meta[:pagination])
32
+ links :next => (pagination[:next] && page_url(pagination[:next])),
33
+ :prev => (pagination[:previous] && page_url(pagination[:previous])),
34
+ :last => (pagination[:pages] && page_url(pagination[:pages])),
35
+ :first => page_url(1)
36
+ end
37
+ end
38
+ end
39
+
40
+ end
41
+ end
@@ -96,10 +96,11 @@ module RocketPants
96
96
  def collection(collection, options = {})
97
97
  pre_process_exposed_object collection, :collection, false
98
98
  options = options.reverse_merge(:compact => true)
99
+ meta = expose_metadata(:count => collection.length)
99
100
  render_json({
100
101
  :response => normalise_object(collection, options),
101
102
  :count => collection.length
102
- }, options)
103
+ }.merge(meta), options)
103
104
  post_process_exposed_object collection, :collection, false
104
105
  end
105
106
 
@@ -107,11 +108,13 @@ module RocketPants
107
108
  def paginated(collection, options = {})
108
109
  pre_process_exposed_object collection, :paginated, false
109
110
  options = options.reverse_merge(:compact => true)
110
- render_json({
111
- :response => normalise_object(collection, options),
111
+ meta = expose_metadata({
112
112
  :count => collection.length,
113
113
  :pagination => Respondable.extract_pagination(collection)
114
- }, options)
114
+ })
115
+ render_json({
116
+ :response => normalise_object(collection, options),
117
+ }.merge(meta), options)
115
118
  post_process_exposed_object collection, :paginated, false
116
119
  end
117
120
 
@@ -146,5 +149,16 @@ module RocketPants
146
149
  def post_process_exposed_object(resource, type, singular)
147
150
  end
148
151
 
152
+ # Given a hash of request metadata, will:
153
+ # 1. Do anything special with the request metadata
154
+ # 2. Return the hash, suitable for merging into the response hash
155
+ # 3. Start a dance party.
156
+ #
157
+ # @param [Hash{Symbol => Object}] metadata the hash of the request metadata.
158
+ # @return [Hash{Symbol => Object}] the passed in metadata
159
+ def expose_metadata(metadata)
160
+ metadata
161
+ end
162
+
149
163
  end
150
164
  end
@@ -1,8 +1,9 @@
1
1
  module RocketPants
2
2
  class Railtie < Rails::Railtie
3
3
 
4
- config.rocket_pants = ActiveSupport::OrderedOptions.new
5
- config.rocket_pants.use_caching = nil
4
+ config.rocket_pants = ActiveSupport::OrderedOptions.new
5
+ config.rocket_pants.use_caching = nil
6
+ config.rocket_pants.header_metadata = nil
6
7
 
7
8
  config.i18n.railties_load_path << File.expand_path('../locale/en.yml', __FILE__)
8
9
 
@@ -14,6 +15,7 @@ module RocketPants
14
15
  rp_config = app.config.rocket_pants
15
16
  rp_config.use_caching = Rails.env.production? if rp_config.use_caching.nil?
16
17
  RocketPants.caching_enabled = rp_config.use_caching
18
+ RocketPants.header_metadata = rp_config.header_metadata unless rp_config.header_metadata.nil?
17
19
  # Set the rocket pants cache if present.
18
20
  RocketPants.cache = rp_config.cache if rp_config.cache
19
21
  end
@@ -52,7 +52,7 @@ module RocketPants
52
52
  end
53
53
 
54
54
  def decoded_count
55
- response.decoded_body.try :count
55
+ response.decoded_body[:count]
56
56
  end
57
57
 
58
58
  def decoded_error_class
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rocket_pants
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  prerelease:
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-05-03 00:00:00.000000000 Z
12
+ date: 2012-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -250,8 +250,10 @@ files:
250
250
  - lib/rocket_pants/controller/caching.rb
251
251
  - lib/rocket_pants/controller/error_handling.rb
252
252
  - lib/rocket_pants/controller/format_verification.rb
253
+ - lib/rocket_pants/controller/header_metadata.rb
253
254
  - lib/rocket_pants/controller/instrumentation.rb
254
255
  - lib/rocket_pants/controller/jsonp.rb
256
+ - lib/rocket_pants/controller/linking.rb
255
257
  - lib/rocket_pants/controller/rescuable.rb
256
258
  - lib/rocket_pants/controller/respondable.rb
257
259
  - lib/rocket_pants/controller/url_for.rb