prismic.io 1.1.1 → 1.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 262cbc2bac7da40a5f91810b4b1e3d3325676f0b
4
- data.tar.gz: fb939276c43de3b25a2f949119650035536afcd2
3
+ metadata.gz: 7458128990b44cfa6672a1397197a242585a7798
4
+ data.tar.gz: 45459748f9aa40d54a83b02e0443be5724afb4dc
5
5
  SHA512:
6
- metadata.gz: e87f7f3f8eb76161cf56b94dbf919215b85963d3dce8f67ff0383987abbcb67f18ab807b14834a2a810f4c5c87fc00ec7f29873b59558c2ddcde1dfddef7340b
7
- data.tar.gz: 14f537c21d1ecee4c18204174e64236911a268f71b49412c4ca4190d984a3f08fab97a36556585329f42e2aa37f42e3a5aa80587a2938389fc1cc40cc5ce2028
6
+ metadata.gz: 23f7794c5ce0d2a6b1b458024faf710a14495c41904a84e72ed752b8e2813fd976fce0cca8c23f68cbe55de3722c8b8dc6daa73067bfa39b6ffdb613c74e85f9
7
+ data.tar.gz: 4510b80711bb3097e254cf0485f4888f7f2d858a20d28b7a77557cb2a2dc654a21dfcdd291996ea874919f7c7fb3b2aebbdcd31b62995b961f1320dc96cf6bc4
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ gemspec
5
5
 
6
6
  group :test do
7
7
  gem "codeclimate-test-reporter", require: nil
8
+ gem 'hashery', '~> 2.1.1'
8
9
  gem "yajl-ruby", require: 'yajl', platforms: [:ruby_19, :ruby_20, :ruby_21]
9
10
  end
10
11
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prismic.io (1.1.1)
4
+ prismic.io (1.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -9,6 +9,7 @@ GEM
9
9
  codeclimate-test-reporter (0.4.1)
10
10
  simplecov (>= 0.7.1, < 1.0.0)
11
11
  diff-lcs (1.2.4)
12
+ hashery (2.1.1)
12
13
  mini_portile (0.5.1)
13
14
  multi_json (1.8.0)
14
15
  nokogiri (1.6.0)
@@ -36,6 +37,7 @@ PLATFORMS
36
37
  DEPENDENCIES
37
38
  bundler (~> 1.3)
38
39
  codeclimate-test-reporter
40
+ hashery (~> 2.1.1)
39
41
  nokogiri (~> 1.6)
40
42
  prismic.io!
41
43
  rspec (~> 2.14)
data/README.md CHANGED
@@ -63,6 +63,11 @@ Knowing all that, here is typical code written with the Ruby kit:
63
63
  * A typical fragment manipulation looks like this: `doc['article.image'].get_view('icon').url`
64
64
  * A typical fragment serialization to HTML looks like this: `doc['article.body'].as_html(@link_resolver)`
65
65
 
66
+ #### Configuring Alternative API Caches
67
+
68
+ The default cache stores data in-memory, in the server. You may want to use a different cache, for example to share it between several servers (with memcached or similar). A null cache (does no caching) is also available if you need a predictible behavior for testing or VCR. To use it (or any other compliant cache), simply add `api_cache => Prismic::BasicNullCache.new`
69
+ to the options passed to `Prismic.api`.
70
+
66
71
  ### Changelog
67
72
 
68
73
  Need to see what changed, or to upgrade your kit? We keep our changelog on [this repository's "Releases" tab](https://github.com/prismicio/ruby-kit/releases).
data/lib/prismic/api.rb CHANGED
@@ -27,18 +27,6 @@ module Prismic
27
27
  !!cache
28
28
  end
29
29
 
30
- # Calls the given block if the provided key is not already cached
31
- #
32
- # If the cache is disabled, the block is always called
33
- #
34
- # @param key [String] the cache's key to test
35
- # @yieldparam key [String] the key
36
- #
37
- # @return the return of the given block
38
- def caching(key)
39
- cache ? cache.get(key){ yield(key) } : yield(key)
40
- end
41
-
42
30
  # Returns the master {Ref reference}
43
31
  # @api
44
32
  #
@@ -121,7 +109,7 @@ module Prismic
121
109
  end
122
110
 
123
111
  # Fetch the API information from the Prismic.io server
124
- def self.get(url, access_token=nil, http_client=Prismic::DefaultHTTPClient, api_cache=Prismic::DefaultApiCache)
112
+ def self.get(url, access_token=nil, http_client=Prismic::DefaultHTTPClient, api_cache=Prismic::DefaultCache)
125
113
  data = {}
126
114
  data['access_token'] = access_token if access_token
127
115
  cache_key = url + (access_token ? ('#' + access_token) : '')
@@ -152,8 +140,10 @@ module Prismic
152
140
  http_client = opts[:http_client] || Prismic::DefaultHTTPClient
153
141
  access_token = opts[:access_token]
154
142
  cache = opts[:cache]
143
+ api_cache = opts[:api_cache]
144
+ api_cache = Prismic::DefaultCache unless api_cache
155
145
  cache ||= Prismic::DefaultCache unless !cache
156
- resp = get(url, access_token, http_client)
146
+ resp = get(url, access_token, http_client, api_cache)
157
147
  json = JSON.load(resp.body)
158
148
  parse_api_response(json, access_token, http_client, cache)
159
149
  end
@@ -1,16 +1,13 @@
1
1
  # encoding: utf-8
2
+
3
+ require 'hashery'
4
+
2
5
  module Prismic
3
6
  # This is a simple cache class provided with the prismic.io Ruby kit.
4
7
  #
5
- # It is pretty dumb but effective:
8
+ # It is pretty dumb but effective: * everything is stored in memory,
6
9
  #
7
- # * everything is stored in memory,
8
- # * invalidation: not needed for prismic.io documents (they are eternally
9
- # immutable), but we don't want the cache to expand indefinitely; therefore
10
- # all cache but the new master ref is cleared when a new master ref gets
11
- # published.
12
- #
13
- # If you need a smarter caching (for instance, caching in files), you can
10
+ # If you need a smarter caching (for instance, rely on memcached), you can
14
11
  # extend this class and replace its methods, and when creating your API object
15
12
  # like this for instance: Prismic.api(url, options), pass the name of the
16
13
  # class you created as a :cache option. Therefore, to use this simple cache,
@@ -18,26 +15,12 @@ module Prismic
18
15
  # Prismic::DefaultCache)`
19
16
  class LruCache
20
17
 
21
- # Based on http://stackoverflow.com/questions/1933866/efficient-ruby-lru-cache
22
- # The Hash are sorted, so the age is represented by the key order
23
-
24
- # Returns the cache object holding the responses to "results" queries (lists
25
- # of documents). The object that is stored as a cache_object is what is
26
- # returned by {Prismic::JsonParser.results_parser} (so that we don't have to
27
- # parse anything again, it's stored already parsed).
28
- #
29
- # @return [Hash<String,Object>]
18
+ # @return [LRUHash<String,Object>]
30
19
  attr_reader :intern
31
20
 
32
- # Returns the maximum of keys to store
33
- #
34
- # @return [Fixum]
35
- attr_reader :max_size
36
-
37
21
  # @param max_size [Fixnum] (100) The default maximum of keys to store
38
22
  def initialize(max_size=100)
39
- @intern = {}
40
- @max_size = max_size
23
+ @intern = Hashery::LRUHash.new(max_size)
41
24
  end
42
25
 
43
26
  # Add a cache entry.
@@ -46,58 +29,56 @@ module Prismic
46
29
  # @param value [Object] The value to store
47
30
  #
48
31
  # @return [Object] The stored value
49
- def store(key, value)
50
- @intern.delete(key)
51
- @intern[key] = value
52
- if @intern.length > @max_size
53
- @intern.delete(@intern.first[0])
54
- end
32
+ def set(key, value, expired_in = nil)
33
+ @intern.store(key, { :data => value, :expired_in => expired_in = expired_in && Time.now.getutc.to_i + expired_in })
55
34
  value
56
35
  end
57
- alias :[]= :store
58
36
 
59
- # Update the maximun number of keys to store
60
- #
61
- # Prune the cache old oldest keys if the new max_size is older than the keys
62
- # number.
63
- #
64
- # @param max_size [Fixnum] The new maximun number of keys to store
65
- def max_size=(max_size)
66
- raise ArgumentError.new(:max_size) if max_size < 1
67
- @max_size = max_size
68
- if @max_size < @intern.size
69
- @intern.keys[0 .. (@max_size-@intern.size)].each { |k|
70
- @intern.delete(k)
71
- }
72
- end
37
+ def []=(key, value)
38
+ set(key, value, nil)
73
39
  end
74
40
 
75
41
  # Get a cache entry
76
42
  #
77
- # A block can be provided: it will be used to compute (and store) the value
78
- # if the key is missing.
79
- #
80
43
  # @param key [String] The key to fetch
81
44
  #
82
45
  # @return [Object] The cache object as was stored
83
46
  def get(key)
84
- found = true
85
- value = @intern.delete(key){ found = false }
86
- if found
87
- @intern[key] = value
47
+ return delete(key) if expired?(key)
48
+ include?(key) ? @intern[key][:data] : nil
49
+ end
50
+ alias :[] :get
51
+
52
+ def get_or_set(key, value = nil, expired_in = nil)
53
+ if include?(key) && !expired?(key)
54
+ return get(key)
88
55
  else
89
- self[key] = yield(key)
56
+ set(key, block_given? ? yield : value, expired_in)
90
57
  end
91
58
  end
92
- alias :[] :get
59
+
60
+ def delete(key)
61
+ @intern.delete(key)
62
+ nil
63
+ end
93
64
 
94
65
  # Checks if a cache entry exists
95
66
  #
96
67
  # @param key [String] The key to test
97
68
  #
98
69
  # @return [Boolean]
99
- def include?(key)
100
- @intern.include?(key)
70
+ def has_key?(key)
71
+ @intern.has_key?(key)
72
+ end
73
+ alias :include? :has_key?
74
+
75
+ def expired?(key)
76
+ if include?(key) && @intern[key][:expired_in] != nil
77
+ expired_in = @intern[key][:expired_in]
78
+ expired_in && expired_in < Time.now.getutc.to_i
79
+ else
80
+ false
81
+ end
101
82
  end
102
83
 
103
84
  # Invalidates all entries
@@ -125,6 +106,18 @@ module Prismic
125
106
 
126
107
  end
127
108
 
109
+ # Available as an api cache for testing purposes (no caching)
110
+ class BasicNullCache
111
+ def get(key)
112
+ end
113
+
114
+ def set(key, value = nil, expired_in = nil)
115
+ block_given? ? yield : value
116
+ end
117
+ alias_method :get_or_set, :set
118
+
119
+ end
120
+
128
121
  # This default instance is used by the API to avoid creating a new instance
129
122
  # per request (which would make the cache useless).
130
123
  DefaultCache = LruCache.new
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  module Prismic
3
3
 
4
- VERSION = '1.1.1'
4
+ VERSION = '1.2.0'
5
5
 
6
6
  end
data/lib/prismic.rb CHANGED
@@ -292,7 +292,10 @@ module Prismic
292
292
  # cache_key is a mix of HTTP URL and HTTP method
293
293
  cache_key = form_method+'::'+form_action+'?'+data.map{|k,v|"#{k}=#{v}"}.join('&')
294
294
 
295
- api.caching(cache_key) {
295
+ from_cache = api.has_cache? && api.cache.get(cache_key)
296
+ if (from_cache)
297
+ from_cache
298
+ else
296
299
  if form_method == 'GET' && form_enctype == 'application/x-www-form-urlencoded'
297
300
  data['access_token'] = api.access_token if api.access_token
298
301
  data.delete_if { |k, v| v.nil? }
@@ -300,6 +303,10 @@ module Prismic
300
303
  response = api.http_client.get(form_action, data, 'Accept' => 'application/json')
301
304
 
302
305
  if response.code.to_s == '200'
306
+ ttl = (response['Cache-Control'] || '').scan(/max-age\s*=\s*(\d+)/).flatten.first
307
+ if ttl != nil && api.has_cache?
308
+ api.cache.set(cache_key, response.body, ttl.to_i)
309
+ end
303
310
  response.body
304
311
  else
305
312
  body = JSON.load(response.body) rescue nil
@@ -312,7 +319,7 @@ module Prismic
312
319
  else
313
320
  raise UnsupportedFormKind, "Unsupported kind of form: #{form_method} / #{enctype}"
314
321
  end
315
- }
322
+ end
316
323
  end
317
324
 
318
325
  # Specify a parameter for this form
@@ -621,4 +628,3 @@ require 'prismic/predicates'
621
628
  require 'prismic/experiments'
622
629
  require 'prismic/json_parsers'
623
630
  require 'prismic/cache/lru'
624
- require 'prismic/cache/basic'
data/spec/cache_spec.rb CHANGED
@@ -49,19 +49,6 @@ describe "Cache's" do
49
49
  it 'can return all keys' do
50
50
  @cache.keys.should == %w(fake_key1 fake_key2 fake_key3)
51
51
  end
52
- it 'deletes oldest key when updating max_size' do
53
- @cache.max_size = 1
54
- @cache.size.should == 1
55
- @cache.include?('fake_key1').should be_false
56
- @cache.include?('fake_key2').should be_false
57
- @cache.include?('fake_key3').should be_true
58
- end
59
- it 'deletes oldest key when adding new one (at max_size)' do
60
- @cache['fake_key4'] = 4
61
- @cache.max_size = 3
62
- @cache.size.should == 3
63
- @cache.include?('fake_key1').should be_false
64
- end
65
52
  it 'keeps readed keys alive' do
66
53
  @cache['fake_key1']
67
54
  @cache['fake_key4'] = 4
@@ -83,25 +70,37 @@ describe "Cache's" do
83
70
  end
84
71
  end
85
72
  end
73
+
74
+ describe 'configurable api cache' do
75
+ let(:api_cache) { Prismic::BasicNullCache.new }
76
+ it 'uses api_cache if provided' do
77
+ expect(api_cache).to receive(:get_or_set).with("https://lesbonneschoses.prismic.io/api", nil, 5).and_call_original.once
78
+ Prismic.api("https://lesbonneschoses.prismic.io/api", api_cache: api_cache)
79
+ end
80
+ it 'uses default cache if not provided' do
81
+ expect(Prismic::DefaultCache).to receive(:get_or_set).with("https://lesbonneschoses.prismic.io/api", nil, 5).and_call_original.once
82
+ Prismic.api("https://lesbonneschoses.prismic.io/api")
83
+ end
84
+ end
86
85
  end
87
86
 
88
- describe "Basic Cache's" do
87
+ describe "LRU Cache's" do
89
88
 
90
89
  it 'set & get value' do
91
- cache = Prismic::BasicCache.new
90
+ cache = Prismic::LruCache.new
92
91
  cache.set('key', 'value')
93
92
  cache.get('key').should == 'value'
94
93
  end
95
94
 
96
95
  it 'set with expiration value & get value' do
97
- cache = Prismic::BasicCache.new
96
+ cache = Prismic::LruCache.new
98
97
  cache.set('key', 'value', 1)
99
98
  sleep(2)
100
99
  cache.get('key').should == nil
101
100
  end
102
101
 
103
102
  it 'set with expiration and a block' do
104
- cache = Prismic::BasicCache.new
103
+ cache = Prismic::LruCache.new
105
104
  cache.get_or_set('key', nil, 1){ 'value' }
106
105
  cache.get_or_set('key', nil, 1){ 'othervalue' }.should == 'value'
107
106
  sleep(2)
@@ -109,13 +108,13 @@ describe "Basic Cache's" do
109
108
  end
110
109
 
111
110
  it 'set & test value' do
112
- cache = Prismic::BasicCache.new
111
+ cache = Prismic::LruCache.new
113
112
  cache.set('key', 'value')
114
113
  cache.include?('key').should == true
115
114
  end
116
115
 
117
116
  it 'get or set value' do
118
- cache = Prismic::BasicCache.new
117
+ cache = Prismic::LruCache.new
119
118
  cache.set('key', 'value')
120
119
  cache.get('key').should == 'value'
121
120
  cache.get_or_set('key', 'value1')
@@ -125,7 +124,7 @@ describe "Basic Cache's" do
125
124
  end
126
125
 
127
126
  it 'set, delete & get value' do
128
- cache = Prismic::BasicCache.new
127
+ cache = Prismic::LruCache.new
129
128
  cache.set('key', 'value')
130
129
  cache.get('key').should == 'value'
131
130
  cache.delete('key')
@@ -133,7 +132,7 @@ describe "Basic Cache's" do
133
132
  end
134
133
 
135
134
  it 'set, clear & get value' do
136
- cache = Prismic::BasicCache.new
135
+ cache = Prismic::LruCache.new
137
136
  cache.expired?('key')
138
137
  cache.set('key', 'value')
139
138
  cache.set('key1', 'value1')
@@ -141,9 +140,30 @@ describe "Basic Cache's" do
141
140
  cache.get('key').should == 'value'
142
141
  cache.get('key1').should == 'value1'
143
142
  cache.get('key2').should == 'value2'
144
- cache.clear()
143
+ cache.clear!
145
144
  cache.get('key').should == nil
146
145
  cache.get('key1').should == nil
147
146
  cache.get('key2').should == nil
148
147
  end
149
148
  end
149
+
150
+ describe 'BasicNullCache' do
151
+ subject { Prismic::BasicNullCache.new }
152
+ it 'always misses' do
153
+ subject.get('key').should == nil
154
+ subject.set('key', 'value').should == 'value'
155
+ subject.get('key').should == nil
156
+ end
157
+ it 'set uses value if no block' do
158
+ subject.set('key', 'value').should == 'value'
159
+ end
160
+ it 'set uses block if provided' do
161
+ subject.set('key', 'value'){'value2'}.should == 'value2'
162
+ end
163
+ it 'get_or_set uses value if no block' do
164
+ subject.get_or_set('key', 'value').should == 'value'
165
+ end
166
+ it 'get_or_set uses block if provided' do
167
+ subject.get_or_set('key', 'value'){'value2'}.should == 'value2'
168
+ end
169
+ end
data/spec/doc_spec.rb CHANGED
@@ -293,7 +293,7 @@ describe 'Documentation' do
293
293
  # startgist:388900d4e9e7a444e0a2:prismic-cache.rb
294
294
  # You can pass any object implementing the same methods as the BasicCache
295
295
  # https://github.com/prismicio/ruby-kit/blob/master/lib/prismic/cache/basic.rb
296
- cache = Prismic::BasicCache.new
296
+ cache = Prismic::LruCache.new
297
297
  api = Prismic::api('https://lesbonneschoses.cdn.prismic.io/api', { :cache => cache })
298
298
  # The Api will use the custom cache object
299
299
  # endgist
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prismic.io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Étienne Vallette d'Osia
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2015-04-09 00:00:00.000000000 Z
14
+ date: 2015-06-05 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -87,7 +87,6 @@ files:
87
87
  - gulpfile.js
88
88
  - lib/prismic.rb
89
89
  - lib/prismic/api.rb
90
- - lib/prismic/cache/basic.rb
91
90
  - lib/prismic/cache/lru.rb
92
91
  - lib/prismic/experiments.rb
93
92
  - lib/prismic/form.rb
@@ -1,66 +0,0 @@
1
- # encoding: utf-8
2
- module Prismic
3
-
4
- class BasicCacheEntry
5
-
6
- attr_reader :expired_in
7
- attr_reader :data
8
-
9
- def initialize(data, expired_in)
10
- @data = data
11
- @expired_in = expired_in
12
- end
13
- end
14
-
15
- class BasicCache
16
-
17
- attr_reader :cache
18
- attr_reader :expirations
19
-
20
- def initialize(data = {})
21
- @cache = {}
22
- end
23
-
24
- def get(key)
25
- return delete(key) if expired?(key)
26
- include?(key) ? @cache[key].data : nil
27
- end
28
-
29
- def set(key, value = nil, expired_in = nil)
30
- data = block_given? ? yield : value
31
- expired_in = expired_in && Time.now.getutc.to_i + expired_in
32
- entry = BasicCacheEntry.new(data, expired_in)
33
- @cache[key] = entry
34
- entry.data
35
- end
36
-
37
- def include?(key)
38
- @cache.keys.include?(key)
39
- end
40
-
41
- def get_or_set(key, value = nil, expired_in = nil)
42
- return get(key) if include?(key) && !expired?(key)
43
- set(key, block_given? ? yield : value, expired_in)
44
- end
45
-
46
- def delete(key)
47
- @cache.delete(key)
48
- nil
49
- end
50
-
51
- def expired?(key)
52
- if include?(key)
53
- expired_in = @cache[key].expired_in
54
- expired_in && expired_in < Time.now.getutc.to_i
55
- else
56
- false
57
- end
58
- end
59
-
60
- def clear()
61
- @cache = {}
62
- end
63
- end
64
-
65
- DefaultApiCache = BasicCache.new
66
- end