stale_options 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7a0e6a29f2972f187cb1732bccd2228d97e4fcc4
4
+ data.tar.gz: a9415cbdc4633d3874a4f74c7d47592c7f644876
5
+ SHA512:
6
+ metadata.gz: 621005d40aef390b2fb9e16f0973e1fef10100b3c4c822859209b29bec5d047266ae3f2ca4ebf2bdebeb3ba07f35093b140df957fe56dbb1b43f653bcba996bc
7
+ data.tar.gz: 4404a71ec56fe989b666f2608ce74cf01d3a6e37807bae31be693abc232648b16d8580edafdbedbcab2e7745ebd6684f3d7216a5a5f9de8bb2f83c4ae9949c18
@@ -0,0 +1 @@
1
+ service_name: travis-ci
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
@@ -0,0 +1,7 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.7
5
+ - 2.4.4
6
+ - 2.5.1
7
+ before_install: gem install bundler -v 1.16.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in stale_options.gemspec
6
+ gemspec
@@ -0,0 +1,62 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ stale_options (0.1.0)
5
+ activerecord (>= 5.0, < 6.0)
6
+ activesupport (>= 5.0, < 6.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activemodel (5.2.0)
12
+ activesupport (= 5.2.0)
13
+ activerecord (5.2.0)
14
+ activemodel (= 5.2.0)
15
+ activesupport (= 5.2.0)
16
+ arel (>= 9.0)
17
+ activesupport (5.2.0)
18
+ concurrent-ruby (~> 1.0, >= 1.0.2)
19
+ i18n (>= 0.7, < 2)
20
+ minitest (~> 5.1)
21
+ tzinfo (~> 1.1)
22
+ arel (9.0.0)
23
+ concurrent-ruby (1.0.5)
24
+ coveralls (0.8.22)
25
+ json (>= 1.8, < 3)
26
+ simplecov (~> 0.16.1)
27
+ term-ansicolor (~> 1.3)
28
+ thor (~> 0.19.4)
29
+ tins (~> 1.6)
30
+ docile (1.3.1)
31
+ i18n (1.0.1)
32
+ concurrent-ruby (~> 1.0)
33
+ json (2.1.0)
34
+ minitest (5.11.3)
35
+ rake (10.5.0)
36
+ simplecov (0.16.1)
37
+ docile (~> 1.1)
38
+ json (>= 1.8, < 3)
39
+ simplecov-html (~> 0.10.0)
40
+ simplecov-html (0.10.2)
41
+ sqlite3 (1.3.13)
42
+ term-ansicolor (1.6.0)
43
+ tins (~> 1.0)
44
+ thor (0.19.4)
45
+ thread_safe (0.3.6)
46
+ tins (1.16.3)
47
+ tzinfo (1.2.5)
48
+ thread_safe (~> 0.1)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ bundler (~> 1.16)
55
+ coveralls (~> 0.8)
56
+ minitest (~> 5.0)
57
+ rake (~> 10.0)
58
+ sqlite3 (~> 1.3)
59
+ stale_options!
60
+
61
+ BUNDLED WITH
62
+ 1.16.2
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Nikolay Digaev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,147 @@
1
+ # StaleOptions
2
+
3
+ [![Build Status](https://travis-ci.org/digaev/stale_options.svg?branch=master)](https://travis-ci.org/digaev/stale_options) [![Coverage Status](https://coveralls.io/repos/github/digaev/stale_options/badge.svg?branch=master)](https://coveralls.io/github/digaev/stale_options?branch=master)
4
+
5
+ A gem for caching HTTP responses.
6
+
7
+ The gem was built with an idea to implement a class which will create options for `ActionController::ConditionalGet#stale?` method, without caring of type of object class.
8
+
9
+ ___
10
+
11
+ * Installation
12
+ * Usage
13
+ * Caching options
14
+ * Examples
15
+ * Controller helpers
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'stale_options'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ ```sh
28
+ bundle
29
+ ```
30
+
31
+ Or install it yourself as:
32
+
33
+ ```sh
34
+ gem install stale_options
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ There are three main classes, each class is designed to create options for the corresponding object class:
40
+
41
+ * `StaleOptions::ArrayOptions` - For caching Arrays.
42
+ * `StaleOptions::RelationOptions` - For caching relations `ActiveRecord::Relation`.
43
+ * `StaleOptions::ObjectOptions` - For caching any other objects.
44
+
45
+ There is also base class `StaleOptions::AbstractOptions`. Constructor of these classes looks like:
46
+
47
+ ```ruby
48
+ def initialize(record, options = {})
49
+ ...
50
+ end
51
+ ```
52
+
53
+ * `record` - Basically any Ruby object. Arrays and relations are "specials".
54
+ * `options` - `Hash`. Caching options (see detailed description in corresponding section).
55
+
56
+ Here is the very basic example of usage:
57
+
58
+ ```
59
+ [1] pry(main)> options = StaleOptions::RelationOptions.new(Item.all)
60
+ [2] pry(main)> options.to_h
61
+ => {:etag=>"39f08c583b023142dd64b0922dfaefd4", :last_modified=>2018-07-04 18:05:22 UTC}
62
+ ```
63
+
64
+ In order to help create different classes of `StaleOptions` for different objects there is method `StaleOptions.create`, so above example can be rewritten like:
65
+
66
+ ```
67
+ [3] pry(main)> StaleOptions.create(Item.all)
68
+ => {:etag=>"39f08c583b023142dd64b0922dfaefd4", :last_modified=>2018-07-04 18:05:22 UTC}
69
+ ```
70
+
71
+ And this is the way how you'll use it in most cases :)
72
+
73
+ ### Caching options
74
+
75
+ There are two options for caching:
76
+
77
+ * `:cache_by`
78
+ * `String` or `Symbol`. A name of method which returns unique identifier of object for caching.
79
+ * For arrays and relations if value is `itself`, then it will be cached "as it is" (relations will be converted to arrays by calling `#to_a`), otherwise this method will be called on each element. *Hint: To cache arrays of "simple" objects (e.g. `String` or `Numeric`) set it to `itself`*.
80
+ * Default: `:updated_at`.
81
+ * `:last_modified`
82
+ * `String` or `Symbol`. A name of method which returns an instance of `ActiveSupport::TimeWithZone`, `DateTime`, `Time`.
83
+ * If `record` is a relation, then an attribute name.
84
+ * If `record` is an `Array` or `Object`, then a method name.
85
+ * `ActiveSupport::TimeWithZone`, `DateTime`, `Time` or `nil` to set `:last_modified`.
86
+ * Default: `:updated_at`.
87
+
88
+ ### Examples
89
+
90
+ ```
91
+ [1] pry(main)> StaleOptions.create(Task.all, last_modified: :done_at)
92
+ => {:etag=>"ce8d2fbc9b815937b59e8815d8a85c21", :last_modified=>2018-06-30 18:25:07 UTC}
93
+
94
+ [2] pry(main)> StaleOptions.create([1, 2, 3], cache_by: :itself, last_modified: nil)
95
+ => {:etag=>"73250e72da5d8950b6bbb16044353d26", :last_modified=>nil}
96
+
97
+ [3] pry(main)> StaleOptions.create({ a: 'a', b: 'b', c: 'c' }, cache_by: :itself, last_modified: Time.now)
98
+ => {:etag=>"fec76eca1192bc7371e44d517b56c93f", :last_modified=>2018-07-08 07:08:48 UTC}
99
+ ```
100
+
101
+ ### Controller helpers
102
+
103
+ In your controller:
104
+
105
+ ```ruby
106
+ # To render a template:
107
+
108
+ class PostsController < ApplicationController
109
+ include StaleOptions::Backend
110
+
111
+ def index
112
+ if_stale?(Post.all) do |posts|
113
+ @posts = posts
114
+ end
115
+ end
116
+ end
117
+
118
+ # Or, to render json:
119
+
120
+ class PostsController < ApplicationController
121
+ include StaleOptions::Backend
122
+
123
+ def index
124
+ if_stale?(Post.all) do |posts|
125
+ render json: posts
126
+ end
127
+ end
128
+ end
129
+ ```
130
+
131
+ Here we're using method `#if_stale?` (there is also `#unless_stale?` btw) which was added to controller by including `StaleOptions::Backend` module. The method accepts two arguments `record` and `options` (yeah, just like `StaleOptions.create`).
132
+
133
+ Under the hood it calls `ActionController::ConditionalGet#stale?` with options created by `StaleOptions.create`:
134
+
135
+ ```ruby
136
+ def if_stale?(record, options = {})
137
+ yield(record) if stale?(StaleOptions.create(record, options))
138
+ end
139
+ ```
140
+
141
+ ## Contributing
142
+
143
+ Bug reports and pull requests are welcome on GitHub at https://github.com/digaev/stale_options.
144
+
145
+ ## License
146
+
147
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "stale_options"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,25 @@
1
+ module StaleOptions
2
+ module Backend
3
+ protected
4
+
5
+ # Usage:
6
+ #
7
+ # class ItemsController < ApplicationController
8
+ # include StaleOptions::Backend
9
+ #
10
+ # def index
11
+ # if_stale?(Item.all) do |items|
12
+ # render json: items
13
+ # end
14
+ # end
15
+ # end
16
+ #
17
+ def if_stale?(record, options = {})
18
+ yield(record) if stale?(StaleOptions.create(record, options))
19
+ end
20
+
21
+ def unless_stale?(record, options = {})
22
+ yield(record) unless stale?(StaleOptions.create(record, options))
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,34 @@
1
+ require 'active_record'
2
+ require 'active_support/time'
3
+
4
+ require 'backend/backend'
5
+
6
+ module StaleOptions
7
+ autoload :AbstractOptions, 'stale_options/abstract_options'
8
+ autoload :ArrayOptions, 'stale_options/array_options'
9
+ autoload :ObjectOptions, 'stale_options/object_options'
10
+ autoload :RelationOptions, 'stale_options/relation_options'
11
+
12
+ def self.create(record, options = {})
13
+ klass =
14
+ case record
15
+ when ActiveRecord::Relation
16
+ RelationOptions
17
+ when Array
18
+ ArrayOptions
19
+ else
20
+ ObjectOptions
21
+ end
22
+
23
+ klass.new(record, options).to_h
24
+ end
25
+
26
+ def self.time?(obj)
27
+ case obj
28
+ when ActiveSupport::TimeWithZone, DateTime, Time
29
+ true
30
+ else
31
+ false
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,84 @@
1
+ module StaleOptions
2
+ class AbstractOptions
3
+ # Params:
4
+ # +record+:: +Object+:: An +Object+, +Array+ or +ActiveRecord::Relation+.
5
+ # +options+:: +Hash+::
6
+ # * +:cache_by+::
7
+ # * +String+ or +Symbol+::
8
+ # A name of method which returns unique identifier of object for caching.
9
+ #
10
+ # For arrays and relations if value is +itself+, then it will be cached as it is,
11
+ # otherwise this method will be called on each element.
12
+ # Relations will be converted to arrays by calling <tt>#to_a</tt>.
13
+ #
14
+ # Hint: To cache an array of "simple" objects (e.g. +String+ or +Numeric+) set it to +itself+.
15
+ # Default: +:updated_at+.
16
+ # * +:last_modified+::
17
+ # * +String+ or +Symbol+::
18
+ # If +record+ is a relation, then an attribute name.
19
+ # If +record+ is an +Array+ or +Object+, then a method name.
20
+ # Expected an instance of +ActiveSupport::TimeWithZone+, +DateTime+, +Time+.
21
+ # * +ActiveSupport::TimeWithZone+, +DateTime+, +Time+ or +nil+::
22
+ # To set +last_modified+.
23
+ # Default: +:updated_at+.
24
+ def initialize(record, options = {})
25
+ @record = record
26
+ @options = {
27
+ cache_by: :updated_at,
28
+ last_modified: :updated_at
29
+ }.merge!(options)
30
+ end
31
+
32
+ # Returns options for <tt>ActionController::ConditionalGet#stale?</tt>
33
+ def to_h
34
+ { etag: etag, last_modified: nil }.tap do |h|
35
+ unless last_modified_opt.nil?
36
+ h[:last_modified] = StaleOptions.time?(last_modified_opt) ? last_modified_opt : last_modified
37
+ h[:last_modified] = h[:last_modified]&.utc
38
+ end
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def cache_by_opt
45
+ @options[:cache_by]
46
+ end
47
+
48
+ def cache_by_itself?
49
+ cache_by_opt.to_s == 'itself'
50
+ end
51
+
52
+ def read_cache_by(obj)
53
+ value = obj.public_send(cache_by_opt)
54
+
55
+ StaleOptions.time?(value) ? value.to_f : value
56
+ end
57
+
58
+ def last_modified_opt
59
+ @options[:last_modified]
60
+ end
61
+
62
+ def read_last_modified(obj)
63
+ obj.public_send(last_modified_opt)
64
+ end
65
+
66
+ def object_hash(obj)
67
+ Digest::MD5.hexdigest(Marshal.dump(obj))
68
+ end
69
+
70
+ def collection_hash(collection)
71
+ object_hash(collection.map { |obj| read_cache_by(obj) })
72
+ end
73
+
74
+ protected
75
+
76
+ def etag
77
+ raise NotImplementedError
78
+ end
79
+
80
+ def last_modified
81
+ raise NotImplementedError
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,21 @@
1
+ module StaleOptions
2
+ class ArrayOptions < AbstractOptions
3
+ private
4
+
5
+ def most_recent
6
+ @most_recent ||= @record.max do |a, b|
7
+ read_last_modified(a) <=> read_last_modified(b)
8
+ end
9
+ end
10
+
11
+ protected
12
+
13
+ def etag
14
+ cache_by_itself? ? object_hash(@record) : collection_hash(@record)
15
+ end
16
+
17
+ def last_modified
18
+ read_last_modified(most_recent) if most_recent
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module StaleOptions
2
+ class ObjectOptions < AbstractOptions
3
+ protected
4
+
5
+ def etag
6
+ object_hash(read_cache_by(@record)) if @record
7
+ end
8
+
9
+ def last_modified
10
+ read_last_modified(@record) if @record
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module StaleOptions
2
+ class RelationOptions < AbstractOptions
3
+ protected
4
+
5
+ def etag
6
+ cache_by_itself? ? object_hash(@record.to_a) : collection_hash(@record)
7
+ end
8
+
9
+ def last_modified
10
+ # FIXME: ActiveRecord#maximum ignores order,
11
+ # so we can't just say `@record.maximum(last_modified_opt)`.
12
+ # See: https://stackoverflow.com/questions/23243828/rails-activerecord-maximumcolumn-ignores-order
13
+
14
+ @record.pluck(last_modified_opt).max
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module StaleOptions
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,32 @@
1
+
2
+ lib = File.expand_path('lib', __dir__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'stale_options/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'stale_options'
8
+ spec.version = StaleOptions::VERSION
9
+ spec.authors = ['Nikolay Digaev']
10
+ spec.email = ['ffs.cmp@gmail.com']
11
+
12
+ spec.summary = 'A gem for caching HTTP responses'
13
+ spec.homepage = 'https://github.com/digaev/stale_options'
14
+ spec.license = 'MIT'
15
+
16
+ # Specify which files should be added to the gem when it is released.
17
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ end
21
+
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_dependency 'activerecord', '>= 5.0', '< 6.0'
25
+ spec.add_dependency 'activesupport', '>= 5.0', '< 6.0'
26
+
27
+ spec.add_development_dependency 'bundler', '~> 1.16'
28
+ spec.add_development_dependency 'coveralls', '~> 0.8'
29
+ spec.add_development_dependency 'minitest', '~> 5.0'
30
+ spec.add_development_dependency 'rake', '~> 10.0'
31
+ spec.add_development_dependency 'sqlite3', '~> 1.3'
32
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stale_options
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Nikolay Digaev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-07-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '5.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: activesupport
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '5.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '6.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '5.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '6.0'
53
+ - !ruby/object:Gem::Dependency
54
+ name: bundler
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '1.16'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '1.16'
67
+ - !ruby/object:Gem::Dependency
68
+ name: coveralls
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '0.8'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '0.8'
81
+ - !ruby/object:Gem::Dependency
82
+ name: minitest
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '5.0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '5.0'
95
+ - !ruby/object:Gem::Dependency
96
+ name: rake
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '10.0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '10.0'
109
+ - !ruby/object:Gem::Dependency
110
+ name: sqlite3
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '1.3'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '1.3'
123
+ description:
124
+ email:
125
+ - ffs.cmp@gmail.com
126
+ executables: []
127
+ extensions: []
128
+ extra_rdoc_files: []
129
+ files:
130
+ - ".coveralls.yml"
131
+ - ".gitignore"
132
+ - ".travis.yml"
133
+ - Gemfile
134
+ - Gemfile.lock
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - bin/console
139
+ - bin/setup
140
+ - lib/backend/backend.rb
141
+ - lib/stale_options.rb
142
+ - lib/stale_options/abstract_options.rb
143
+ - lib/stale_options/array_options.rb
144
+ - lib/stale_options/object_options.rb
145
+ - lib/stale_options/relation_options.rb
146
+ - lib/stale_options/version.rb
147
+ - stale_options.gemspec
148
+ homepage: https://github.com/digaev/stale_options
149
+ licenses:
150
+ - MIT
151
+ metadata: {}
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubyforge_project:
168
+ rubygems_version: 2.6.14
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: A gem for caching HTTP responses
172
+ test_files: []