tml 4.3.12 → 4.4.1

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: eedcd1e0845ace035f6e6b15b8a91e6376f78a8f
4
- data.tar.gz: 9f20b2e4fb6022af375b506f0d829289916533c9
3
+ metadata.gz: 219ec288ae06a6e1f41055d5a43911f912a9a60b
4
+ data.tar.gz: af5bb4eb638a821d605611fe3dfdb0eb3bfd1ef1
5
5
  SHA512:
6
- metadata.gz: b1e8412ce5d6beeadbbaf8ed073352cca9d55f437280c4c13b5e17a8d8a93d7c92da25ee6336bc8295f29ce25a09b5157917a6b9d5143efefd811b397aba17ba
7
- data.tar.gz: 06642e956d2dddbeff5cbc2a9d5e2bc8e4118e96e7667a20f3295da84ebfc612c0ca56e8645ca9c1009e2af65d91061068a2a9c9e91d7e4c4e08938d519bbdc3
6
+ metadata.gz: 284ba13aed6ef6aff3a8b016edf77d8e9e844e587fd80e4d8029e8fe2904552f7c5d75b91e31ea7173ab0bdcae24f8ffc6f3e19396d632322f566e120b5e3b85
7
+ data.tar.gz: a53fe934ba88ef001c8ab23c8f8ac14344397f5240d0ffb330bf5ac8d6967a02943c97505bea742ca0ea3d7b6a8bd023863eb29a40639b8e44d41e4f9d2c2656
@@ -33,15 +33,13 @@
33
33
  require 'faraday'
34
34
 
35
35
  class Tml::Api::Client < Tml::Base
36
+ CDN_HOST = 'https://cdn.translationexchange.com'
36
37
  API_HOST = 'https://api.translationexchange.com'
37
38
  API_PATH = '/v1'
38
39
 
39
40
  attributes :application
40
41
 
41
- def access_token
42
- Tml.config.application[:token] || Tml.config.application[:access_token]
43
- end
44
-
42
+ # get results from api
45
43
  def results(path, params = {}, opts = {})
46
44
  get(path, params, opts)['results']
47
45
  end
@@ -78,14 +76,61 @@ class Tml::Api::Client < Tml::Base
78
76
  end
79
77
  end
80
78
 
81
- def api(path, params = {}, opts = {})
82
- if Tml.session.inline_mode?
83
- return process_response(execute_request(path, params, opts), opts)
79
+ def verify_cache_version
80
+ return if Tml.cache.version and Tml.cache.version != 'undefined'
81
+
82
+ current_version = Tml.cache.fetch_version
83
+ if current_version == 'undefined'
84
+ Tml.cache.store_version(execute_request('applications/current/version', {}, {:raw => true}))
85
+ else
86
+ Tml.cache.version = current_version
87
+ end
88
+ Tml.logger.info("Version: #{Tml.cache.version}")
89
+ end
90
+
91
+ def cdn_connection
92
+ @cdn_connection ||= Faraday.new(:url => CDN_HOST) do |faraday|
93
+ faraday.request(:url_encoded) # form-encode POST params
94
+ faraday.adapter(Faraday.default_adapter) # make requests with Net::HTTP
95
+ end
96
+ end
97
+
98
+ def get_from_cdn(key, params = {}, opts = {})
99
+ return nil if Tml.cache.version == 'undefined' || Tml.cache.version.to_s == '0'
100
+
101
+ response = nil
102
+ cdn_path = "#{Tml.config.access_token}/#{Tml.cache.version}/#{key}.json"
103
+ trace_api_call(cdn_path, params, opts) do
104
+ begin
105
+ response = cdn_connection.get(cdn_path, params)
106
+ rescue Exception => ex
107
+ Tml.logger.error("Failed to execute request: #{ex.message[0..255]}")
108
+ return nil
109
+ end
84
110
  end
111
+ return if response.status >= 500 and response.status < 600
112
+ return if response.body.nil? or response.body == '' or response.body.match(/xml/)
85
113
 
86
- if opts[:method] == :get and opts[:cache_key]
114
+ begin
115
+ data = JSON.parse(response.body)
116
+ rescue Exception => ex
117
+ return nil
118
+ end
119
+
120
+ data
121
+ end
122
+
123
+ def api(path, params = {}, opts = {})
124
+ # inline mode should always bypass API calls
125
+ # get request uses local cache, then CDN, the API
126
+ if opts[:method] == :get and opts[:cache_key] and Tml.cache.enabled? and not Tml.session.inline_mode?
127
+ verify_cache_version
87
128
  data = Tml.cache.fetch(opts[:cache_key]) do
88
- Tml.cache.read_only? ? nil : execute_request(path, params, opts)
129
+ if Tml.cache.read_only?
130
+ nil
131
+ else
132
+ get_from_cdn(opts[:cache_key]) || execute_request(path, params, opts)
133
+ end
89
134
  end
90
135
  process_response(data, opts)
91
136
  else
@@ -125,7 +170,7 @@ class Tml::Api::Client < Tml::Base
125
170
 
126
171
  # oauth path is separate from versioned APIs
127
172
  path = prepare_api_path(path)
128
- params = params.merge(:access_token => access_token) unless path.index('oauth')
173
+ params = params.merge(:access_token => Tml.config.access_token) unless path.index('oauth')
129
174
 
130
175
  if opts[:method] == :post
131
176
  params = params.merge(:api_key => application.key)
@@ -155,6 +200,7 @@ class Tml::Api::Client < Tml::Base
155
200
  end
156
201
 
157
202
  return if response.body.nil? or response.body == ''
203
+ return response.body if opts[:raw]
158
204
 
159
205
  begin
160
206
  data = JSON.parse(response.body)
@@ -206,7 +252,7 @@ class Tml::Api::Client < Tml::Base
206
252
  #end
207
253
 
208
254
  if opts[:method] == :post
209
- Tml.logger.debug("post: [#{path}] #{params.inspect}")
255
+ Tml.logger.debug("post: [#{path}]")
210
256
  else
211
257
  Tml.logger.debug("get: #{path}?#{to_query(params)}")
212
258
  end
@@ -137,7 +137,7 @@ class Tml::Application < Tml::Base
137
137
  end
138
138
 
139
139
  def register_missing_key(source_key, tkey)
140
- return if Tml.cache.read_only? and not Tml.session.inline_mode?
140
+ return if Tml.cache.enabled? and not Tml.session.inline_mode?
141
141
 
142
142
  @missing_keys_by_sources ||= {}
143
143
  @missing_keys_by_sources[source_key] ||= {}
@@ -32,7 +32,7 @@
32
32
 
33
33
  module Tml
34
34
 
35
- CACHE_VERSION_KEY = '__tml_version__'
35
+ CACHE_VERSION_KEY = 'current_version'
36
36
 
37
37
  def self.memory
38
38
  @memory ||= Tml::CacheAdapters::Memory.new
@@ -52,92 +52,105 @@ module Tml
52
52
 
53
53
  class Cache
54
54
 
55
+ # Returns current cache version
55
56
  def version
56
- Tml.config.cache[:version] ||= 1
57
-
58
- @version ||= begin
59
- v = fetch(CACHE_VERSION_KEY) do
60
- {'version' => Tml.config.cache[:version]}
61
- end
62
- v['version']
63
- end
64
-
65
- @version ||= Tml.config.cache[:version]
66
-
67
- if Tml.config.cache[:version] > @version
68
- update_version(Tml.config.cache[:version])
69
- @version = Tml.config.cache[:version]
70
- end
71
-
72
57
  @version
73
58
  end
74
59
 
75
- def update_version(new_version)
76
- store(CACHE_VERSION_KEY, {'version' => new_version}, :ttl => 0)
60
+ # sets the current version
61
+ def version=(new_version)
62
+ @version = new_version
77
63
  end
78
64
 
79
- def upgrade_version
80
- update_version((version || Tml.config.cache[:version] || 0).to_i + 1)
65
+ # resets current version
66
+ def reset_version
81
67
  @version = nil
82
68
  end
83
69
 
84
- def reset_version
85
- @version = nil
70
+ # upgrade current version
71
+ def upgrade_version
72
+ store(CACHE_VERSION_KEY, {'version' => 'undefined'})
73
+ reset_version
86
74
  end
87
75
 
88
- def enabled?
89
- Tml.config.cache[:enabled]
76
+ # fetches the version from the cache
77
+ def fetch_version
78
+ @version ||= begin
79
+ v = fetch(CACHE_VERSION_KEY) do
80
+ {'version' => Tml.config.cache[:version] || 'undefined'}
81
+ end
82
+ v.is_a?(Hash) ? v['version'] : v
83
+ end
90
84
  end
91
85
 
92
- def cached_by_source?
93
- true
86
+ # stores the current version back in cache
87
+ def store_version(new_version)
88
+ @version = new_version
89
+ store(CACHE_VERSION_KEY, {'version' => new_version})
94
90
  end
95
91
 
96
- def read_only?
97
- false
92
+ # checks if Tml is enabled
93
+ def enabled?
94
+ Tml.config.cache_enabled?
98
95
  end
99
96
 
100
- def segmented?
101
- true
97
+ # by default all cache is read/write
98
+ # cache like files based should be set to read only
99
+ def read_only?
100
+ false
102
101
  end
103
102
 
103
+ # name of the cache adapter
104
104
  def cache_name
105
105
  self.class.name.split('::').last
106
106
  end
107
107
 
108
+ # logs information messages
108
109
  def info(msg)
109
110
  Tml.logger.info("#{cache_name} - #{msg}")
110
111
  end
111
112
 
113
+ # logs a warning
112
114
  def warn(msg)
113
115
  Tml.logger.warn("#{cache_name} - #{msg}")
114
116
  end
115
117
 
118
+ # namespace of each cache key
119
+ def namespace
120
+ return '#' if Tml.config.disabled?
121
+ Tml.config.cache[:namespace] || Tml.config.access_token[0..5]
122
+ end
123
+
124
+ # versioned name of cache key
116
125
  def versioned_key(key, opts = {})
117
- return key if CACHE_VERSION_KEY == key
118
- "tml_rc_v#{version}_#{key}"
126
+ "tml_#{namespace}#{CACHE_VERSION_KEY == key ? '' : "_v#{version}"}_#{key}"
119
127
  end
120
128
 
129
+ # fetches key from cache
121
130
  def fetch(key, opts = {})
122
131
  return nil unless block_given?
123
132
  yield
124
133
  end
125
134
 
135
+ # stores key in cache
126
136
  def store(key, data, opts = {})
127
137
  # do nothing
128
138
  end
129
139
 
140
+ # deletes key from cache
130
141
  def delete(key, opts = {})
131
142
  # do nothing
132
143
  end
133
144
 
145
+ # checks if the key exists
134
146
  def exist?(key, opts = {})
135
147
  false
136
148
  end
137
149
 
150
+ # clears cache
138
151
  def clear(opts = {})
139
152
  # do nothing
140
153
  end
141
154
 
142
155
  end
143
- end
156
+ end
@@ -48,11 +48,6 @@ class Tml::CacheAdapters::File < Tml::Cache
48
48
  'file'
49
49
  end
50
50
 
51
- def segmented?
52
- return true if Tml.config.cache[:segmented].nil?
53
- Tml.config.cache[:segmented]
54
- end
55
-
56
51
  def fetch(key, opts = {})
57
52
  if self.class.cache[key]
58
53
  info("Memory hit: #{key}")
@@ -71,10 +71,11 @@ class Tml::CacheAdapters::Memcache < Tml::Cache
71
71
 
72
72
  def store(key, data, opts = {})
73
73
  info("Cache store: #{key}")
74
- ttl = opts[:ttl] || Tml.config.cache[:timeout]
74
+ ttl = opts[:ttl] || Tml.config.cache[:timeout] || 0
75
75
  @cache.set(versioned_key(key, opts), data, ttl)
76
76
  data
77
77
  rescue Exception => ex
78
+ pp ex
78
79
  warn("Failed to store data: #{key}")
79
80
  data
80
81
  end
@@ -61,7 +61,7 @@ class Tml::CacheAdapters::Redis < Tml::Cache
61
61
  def fetch(key, opts = {})
62
62
  data = @cache.get(versioned_key(key, opts))
63
63
  if data
64
- info("Cache hit: #{key}")
64
+ info("Cache hit: #{key} #{data}")
65
65
 
66
66
  begin
67
67
  return JSON.parse(data)
@@ -78,7 +78,7 @@ module Tml
78
78
  attr_accessor :enabled, :default_locale, :default_level, :format, :application, :context_rules, :logger, :cache, :default_tokens, :localization
79
79
 
80
80
  # Used by Rails and Sinatra extensions
81
- attr_accessor :current_locale_method, :current_user_method, :translator_options
81
+ attr_accessor :current_locale_method, :current_user_method, :translator_options, :i18n_backend
82
82
 
83
83
  # Used for IRB only
84
84
  attr_accessor :submit_missing_keys_realtime
@@ -166,11 +166,7 @@ module Tml
166
166
  }
167
167
 
168
168
  @cache = {
169
- :enabled => false,
170
- :host => 'localhost:11211',
171
- :adapter => 'memcache',
172
- :version => 1,
173
- :timeout => 3600
169
+ :enabled => false
174
170
  }
175
171
 
176
172
  @default_tokens = {
@@ -343,6 +339,10 @@ module Tml
343
339
  @default_application ||= Tml::Application.new(:host => Tml::Api::Client::API_HOST)
344
340
  end
345
341
 
342
+ def access_token
343
+ @application[:token] || @application[:access_token] || ''
344
+ end
345
+
346
346
  #########################################################
347
347
  ## Decorations
348
348
  #########################################################
@@ -50,7 +50,11 @@ class Tml::Decorators::Html < Tml::Decorators::Base
50
50
  # return translated_label unless Tml.session.current_translator.feature_enabled?(:show_locked_keys)
51
51
  classes << 'tml_locked'
52
52
  elsif translation_language == translation_key.language
53
- classes << 'tml_not_translated'
53
+ if options[:pending]
54
+ classes << 'tml_pending'
55
+ else
56
+ classes << 'tml_not_translated'
57
+ end
54
58
  elsif translation_language == target_language
55
59
  classes << 'tml_translated'
56
60
  else
@@ -155,16 +155,14 @@ class Tml::Language < Tml::Base
155
155
 
156
156
  source_key = current_source(options)
157
157
 
158
- if Tml.cache.segmented? or Tml.session.inline_mode?
159
- source = application.source(source_key, locale)
160
- cached_translations = source.cached_translations(locale, translation_key.key)
161
- else
162
- cached_translations = application.fetch_translations(locale)[translation_key.key]
163
- end
158
+ source = application.source(source_key, locale)
159
+ cached_translations = source.cached_translations(locale, translation_key.key)
164
160
 
165
161
  if cached_translations
166
162
  translation_key.set_translations(locale, cached_translations)
167
163
  else
164
+ params[:options] ||= {}
165
+ params[:options][:pending] = true
168
166
  application.register_missing_key(source_key, translation_key)
169
167
  end
170
168
 
@@ -58,50 +58,44 @@ module Tml
58
58
  class Logger < ::Logger
59
59
  attr_accessor :external_logger
60
60
 
61
- def info(message)
62
- if external_logger
63
- return external_logger.info(format_message(Logger::Severity::INFO, Time.new, nil, message))
64
- end
61
+ def log_to_console(msg)
62
+ return unless Tml.config.logger[:console]
63
+ puts msg
64
+ end
65
65
 
66
+ def info(message)
67
+ log_to_console(message)
68
+ return external_logger.info(format_message(Logger::Severity::INFO, Time.new, nil, message)) if external_logger
66
69
  super
67
70
  end
68
71
 
69
72
  def debug(message)
70
- if external_logger
71
- return external_logger.debug(format_message(Logger::Severity::DEBUG, Time.new, nil, message))
72
- end
73
-
73
+ log_to_console(message)
74
+ return external_logger.debug(format_message(Logger::Severity::DEBUG, Time.new, nil, message)) if external_logger
74
75
  super
75
76
  end
76
77
 
77
78
  def warn(message)
78
- if external_logger
79
- return external_logger.warn(format_message(Logger::Severity::WARN, Time.new, nil, message))
80
- end
81
-
79
+ log_to_console(message)
80
+ return external_logger.warn(format_message(Logger::Severity::WARN, Time.new, nil, message)) if external_logger
82
81
  super
83
82
  end
84
83
 
85
84
  def error(message)
86
- if external_logger
87
- return external_logger.error(format_message(Logger::Severity::ERROR, Time.new, nil, message))
88
- end
89
-
85
+ log_to_console(message)
86
+ return external_logger.error(format_message(Logger::Severity::ERROR, Time.new, nil, message)) if external_logger
90
87
  super
91
88
  end
92
89
 
93
90
  def fatal(message)
94
- if external_logger
95
- return external_logger.fatal(format_message(Logger::Severity::FATAL, Time.new, nil, message))
96
- end
97
-
91
+ log_to_console(message)
92
+ return external_logger.fatal(format_message(Logger::Severity::FATAL, Time.new, nil, message)) if external_logger
98
93
  super
99
94
  end
100
95
 
101
96
  def format_message(severity, timestamp, progname, msg)
102
- return "" unless Tml.config.logger[:enabled]
103
- # TODO: check for severity/level
104
- "[#{timestamp.strftime("%D %T")}]: tml: #{' ' * stack.size}#{msg}\n"
97
+ return '' unless Tml.config.logger[:enabled]
98
+ "[#{timestamp.strftime('%D %T')}]: tml: #{' ' * stack.size}#{msg}\n"
105
99
  end
106
100
 
107
101
  def add(severity, message = nil, progname = nil, &block)
@@ -41,7 +41,7 @@ module Tml
41
41
  :current_source, :current_component, :block_options, :cookie_params, :access_token, :tools_enabled
42
42
 
43
43
  def cookie_name
44
- "trex_#{self.application.key}"
44
+ "trex_#{Tml.config.access_token[0..19]}_translationexchange"
45
45
  end
46
46
 
47
47
  def init(opts = {})
@@ -51,10 +51,6 @@ module Tml
51
51
 
52
52
  Tml.cache.reset_version
53
53
 
54
- self.application = Tml::Application.new(:host => host).fetch
55
-
56
- # Tml.logger.info(self.cookie_params.inspect)
57
-
58
54
  self.cookie_params = begin
59
55
  if opts[:cookies] and opts[:cookies][cookie_name]
60
56
  begin
@@ -70,6 +66,8 @@ module Tml
70
66
  end
71
67
  end
72
68
 
69
+ # Tml.logger.info(self.cookie_params.inspect)
70
+
73
71
  self.tools_enabled = opts[:tools_enabled]
74
72
  self.current_user = opts[:user]
75
73
  self.current_source = opts[:source] || 'index'
@@ -80,6 +78,8 @@ module Tml
80
78
  self.current_translator = Tml::Translator.new(self.cookie_params['translator'])
81
79
  end
82
80
 
81
+ self.application = Tml::Application.new(:host => host).fetch
82
+
83
83
  # if inline mode don't use any app cache
84
84
  if inline_mode?
85
85
  self.application = self.application.dup
@@ -76,6 +76,8 @@ class Tml::Source < Tml::Base
76
76
  {:cache_key => Tml::Source.cache_key(locale, self.source)}
77
77
  )
78
78
 
79
+ return self unless results
80
+
79
81
  results.each do |key, data|
80
82
  translations_data = data.is_a?(Hash) ? data['translations'] : data
81
83
  self.translations[locale][key] = translations_data.collect do |t|
@@ -30,5 +30,5 @@
30
30
  #++
31
31
 
32
32
  module Tml
33
- VERSION = '4.3.12'
33
+ VERSION = '4.4.1'
34
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tml
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.12
4
+ version: 4.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Berkovich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-26 00:00:00.000000000 Z
11
+ date: 2015-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -54,7 +54,6 @@ files:
54
54
  - lib/tml/application.rb
55
55
  - lib/tml/base.rb
56
56
  - lib/tml/cache.rb
57
- - lib/tml/cache_adapters/cdn.rb
58
57
  - lib/tml/cache_adapters/file.rb
59
58
  - lib/tml/cache_adapters/memcache.rb
60
59
  - lib/tml/cache_adapters/redis.rb
@@ -1,101 +0,0 @@
1
- # encoding: UTF-8
2
- #--
3
- # Copyright (c) 2015 Translation Exchange, Inc
4
- #
5
- # _______ _ _ _ ______ _
6
- # |__ __| | | | | (_) | ____| | |
7
- # | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
8
- # | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
9
- # | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
10
- # |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
11
- # __/ |
12
- # |___/
13
- # Permission is hereby granted, free of charge, to any person obtaining
14
- # a copy of this software and associated documentation files (the
15
- # "Software"), to deal in the Software without restriction, including
16
- # without limitation the rights to use, copy, modify, merge, publish,
17
- # distribute, sublicense, and/or sell copies of the Software, and to
18
- # permit persons to whom the Software is furnished to do so, subject to
19
- # the following conditions:
20
- #
21
- # The above copyright notice and this permission notice shall be
22
- # included in all copies or substantial portions of the Software.
23
- #
24
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
- #++
32
-
33
- class Tml::CacheAdapters::Cdn < Tml::Cache
34
-
35
- def self.cache
36
- @cache ||= {}
37
- end
38
-
39
- def self.cache_path
40
- "#{Tml.config.cache[:base_url]}/#{Tml.config.cache[:version]}"
41
- end
42
-
43
- def self.cdn_path(key)
44
- File.join(cache_path, "#{key}.json")
45
- end
46
-
47
- def cache_name
48
- 'cdn'
49
- end
50
-
51
- def segmented?
52
- return true if Tml.config.cache[:segmented].nil?
53
- Tml.config.cache[:segmented]
54
- end
55
-
56
- def fetch(key, opts = {})
57
- if self.class.cache[key]
58
- info("Memory hit: #{key}")
59
- return self.class.cache[key]
60
- end
61
-
62
- path = self.class.cdn_path(key)
63
-
64
-
65
- # load data from cdn
66
-
67
-
68
- if File.exists?(path)
69
- info("Cache hit: #{key}")
70
- self.class.cache[key] = JSON.parse(File.read(path))
71
- return self.class.cache[key]
72
- end
73
-
74
- info("Cache miss: #{key}")
75
-
76
- return nil unless block_given?
77
-
78
- yield
79
- end
80
-
81
- def store(key, data, opts = {})
82
- warn('This is a readonly cache')
83
- end
84
-
85
- def delete(key, opts = {})
86
- warn('This is a readonly cache')
87
- end
88
-
89
- def exist?(key, opts = {})
90
- File.exists?(self.class.file_path(key))
91
- end
92
-
93
- def clear(opts = {})
94
- warn('This is a readonly cache')
95
- end
96
-
97
- def read_only?
98
- true
99
- end
100
-
101
- end