prismic.io 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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