has_many_scored 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d6e3ceacfc424710a369f2556276c3593353e762
4
+ data.tar.gz: d568b6e4ac4122bad8fa8df24d6609101a0e75a4
5
+ SHA512:
6
+ metadata.gz: f7c91444fa1250d1be8845623db6d3190a7e2e2012fa9f1cb80b67f1c78b9f5cef808e98ff85f6d2b81b65469a27fcabc7b018ca1bc76d3d88d22f220b575f51
7
+ data.tar.gz: 58a2fda5405b98b228f89c0bef26bd6475378a4666481ce5c77bab28164b81e2a2b6fe3a6467a4249edd2db678121634d12f2aaff87d58992e959cbb967a59ff
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/ChangeLog.rdoc ADDED
@@ -0,0 +1,4 @@
1
+ === 1.0.0 / 2014-02-15
2
+
3
+ * Initial release
4
+ * Stuff works
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in has_many_scored.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,72 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ has_many_scored (0.0.1)
5
+ activerecord (>= 3.0, <= 4.0.2)
6
+ redis-objects (>= 0.6.1)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activemodel (4.0.2)
12
+ activesupport (= 4.0.2)
13
+ builder (~> 3.1.0)
14
+ activerecord (4.0.2)
15
+ activemodel (= 4.0.2)
16
+ activerecord-deprecated_finders (~> 1.0.2)
17
+ activesupport (= 4.0.2)
18
+ arel (~> 4.0.0)
19
+ activerecord-deprecated_finders (1.0.3)
20
+ activesupport (4.0.2)
21
+ i18n (~> 0.6, >= 0.6.4)
22
+ minitest (~> 4.2)
23
+ multi_json (~> 1.3)
24
+ thread_safe (~> 0.1)
25
+ tzinfo (~> 0.3.37)
26
+ arel (4.0.2)
27
+ atomic (1.1.14)
28
+ builder (3.1.4)
29
+ coderay (1.1.0)
30
+ diff-lcs (1.2.5)
31
+ fakeredis (0.4.3)
32
+ redis (~> 3.0.0)
33
+ i18n (0.6.9)
34
+ json (1.8.1)
35
+ method_source (0.8.2)
36
+ minitest (4.7.5)
37
+ multi_json (1.8.4)
38
+ pry (0.9.12.4)
39
+ coderay (~> 1.0)
40
+ method_source (~> 0.8)
41
+ slop (~> 3.4)
42
+ rdoc (4.1.1)
43
+ json (~> 1.4)
44
+ redis (3.0.7)
45
+ redis-objects (0.9.0)
46
+ redis (>= 3.0.2)
47
+ rspec (2.14.1)
48
+ rspec-core (~> 2.14.0)
49
+ rspec-expectations (~> 2.14.0)
50
+ rspec-mocks (~> 2.14.0)
51
+ rspec-core (2.14.7)
52
+ rspec-expectations (2.14.5)
53
+ diff-lcs (>= 1.1.3, < 2.0)
54
+ rspec-mocks (2.14.5)
55
+ rubygems-tasks (0.2.4)
56
+ slop (3.4.7)
57
+ sqlite3 (1.3.8)
58
+ thread_safe (0.1.3)
59
+ atomic
60
+ tzinfo (0.3.38)
61
+
62
+ PLATFORMS
63
+ ruby
64
+
65
+ DEPENDENCIES
66
+ fakeredis
67
+ has_many_scored!
68
+ pry
69
+ rdoc (~> 4.1.0)
70
+ rspec (~> 2.4)
71
+ rubygems-tasks (~> 0.2)
72
+ sqlite3
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Hsiu-Fan Wang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ 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, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # has_many_scored
2
+
3
+ ## Description
4
+
5
+ An ActiveRecord plugin that combines an ordered habtm-like association with optional redis caching.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'has_many_scored'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install has_many_scored
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( http://github.com/hfwang/has_many_scored/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ require "bundler/gem_tasks"
4
+ require 'rake'
5
+
6
+ begin
7
+ gem 'rdoc'
8
+ require 'rdoc/task'
9
+
10
+ RDoc::Task.new do |rdoc|
11
+ rdoc.title = "has_many_scored"
12
+ end
13
+ rescue LoadError => e
14
+ warn e.message
15
+ warn "Run `gem install rdoc` to install 'rdoc/task'."
16
+ end
17
+ task :doc => :rdoc
18
+
19
+ begin
20
+ gem 'rspec', '~> 2.4'
21
+ require 'rspec/core/rake_task'
22
+
23
+ RSpec::Core::RakeTask.new
24
+ rescue LoadError => e
25
+ task :spec do
26
+ abort "Please run `gem install rspec` to install RSpec."
27
+ end
28
+ end
29
+
30
+ task :test => :spec
31
+ task :default => :spec
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path("../lib/has_many_scored/version", __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "has_many_scored"
7
+ gem.version = HasManyScored::VERSION
8
+ gem.summary = %q{An ActiveRecord plugin that combines an ordered habtm-like association with optional redis caching}
9
+ gem.description = %q{An ActiveRecord plugin that combines an ordered habtm-like association with optional redis caching.}
10
+ gem.license = "MIT"
11
+ gem.authors = ["Hsiu-Fan Wang"]
12
+ gem.email = "hfwang@porkbuns.net"
13
+ gem.homepage = "https://rubygems.org/gems/has_many_scored"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency("activerecord", ">= 3.0", "<= 4.0.2")
21
+ gem.add_dependency("redis-objects", ">= 0.6.1")
22
+
23
+ gem.add_development_dependency "pry"
24
+ gem.add_development_dependency "sqlite3"
25
+ gem.add_development_dependency "fakeredis"
26
+ gem.add_development_dependency "rdoc", "~> 4.1.0"
27
+ gem.add_development_dependency "rspec", "~> 2.4"
28
+ gem.add_development_dependency "rubygems-tasks", "~> 0.2"
29
+ end
@@ -0,0 +1,38 @@
1
+ module HasManyScored
2
+ # This module is used to extend the join model and mix in additional logic
3
+ module HasManyScoredExtension
4
+ def self.bind_extension(options)
5
+ return Proc.new do
6
+ include HasManyScored::HasManyScoredExtension
7
+
8
+ # Options is defined using define_method so opts can still be within scope.
9
+ define_method :options do
10
+ return options
11
+ end
12
+ end
13
+ end
14
+
15
+ def update_score(*records)
16
+ join_table = proxy_association.join_table
17
+ reflection = proxy_association.reflection
18
+
19
+ records.each do |record|
20
+ update_manager = Arel::UpdateManager.new(join_table.engine)
21
+ update_manager.table(join_table)\
22
+ .set(join_table[options[:score_column]] => self.compute_score(record))\
23
+ .where(join_table[reflection.foreign_key].eq(proxy_association.owner.id))\
24
+ .where(join_table[reflection.association_foreign_key].eq(record.id))\
25
+ .take(1)
26
+ proxy_association.owner.connection.execute(update_manager.to_sql)
27
+ end
28
+
29
+ reset
30
+
31
+ self
32
+ end
33
+
34
+ def compute_score(record)
35
+ record.send(options[:score_field])
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,40 @@
1
+ module HasManyScored
2
+ # This module is used to extend the join model and mix in additional logic
3
+ module ScoredForManyExtension
4
+ def self.bind_extension(options)
5
+ return Proc.new do
6
+ include HasManyScored::ScoredForManyExtension
7
+
8
+ # Options is defined using define_method so opts can still be within scope.
9
+ define_method :options do
10
+ return options
11
+ end
12
+ end
13
+ end
14
+
15
+ def update_score(*records)
16
+ join_table = proxy_association.join_table
17
+ reflection = proxy_association.reflection
18
+
19
+ owner_score = self.compute_score(proxy_association.owner)
20
+
21
+ records.each do |record|
22
+ update_manager = Arel::UpdateManager.new(join_table.engine)
23
+ update_manager.table(join_table)\
24
+ .set(join_table[options[:score_column]] => owner_score)\
25
+ .where(join_table[reflection.foreign_key].eq(proxy_association.owner.id))\
26
+ .where(join_table[reflection.association_foreign_key].eq(record.id))\
27
+ .take(1)
28
+ proxy_association.owner.connection.execute(update_manager.to_sql)
29
+ end
30
+
31
+ reset
32
+
33
+ self
34
+ end
35
+
36
+ def compute_score(record)
37
+ record.send(options[:score_field])
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module HasManyScored
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,63 @@
1
+ require "has_many_scored/version"
2
+ require "has_many_scored/has_many_scored_extension"
3
+ require "has_many_scored/scored_for_many_extension"
4
+
5
+ module HasManyScored
6
+ module ClassMethods
7
+ VALID_HABTM_OPTIONS = [:class_name, :join_table, :foreign_key,
8
+ :association_foreign_key, :readonly, :validate,
9
+ :autosave]
10
+
11
+ def has_many_scored(name, opts=nil)
12
+ opts = opts.try(:dup) || {}
13
+
14
+ habtm_opts = opts.select { |k, v| VALID_HABTM_OPTIONS.include?(k) }
15
+ habtm_opts[:insert_sql] = lambda { |record|
16
+ proxy_association = self.association(name)
17
+ join_table = proxy_association.join_table
18
+ reflection = proxy_association.reflection
19
+
20
+ return join_table.compile_insert(
21
+ join_table[reflection.foreign_key] => self.id,
22
+ join_table[reflection.association_foreign_key] => record.id,
23
+ join_table[opts[:score_column]] => proxy_association.scope.compute_score(record))
24
+ }
25
+
26
+ opts[:score_column] ||= :score
27
+ opts[:score_field] ||= :score
28
+
29
+ has_and_belongs_to_many(
30
+ name,
31
+ lambda { |owner| order("#{owner.association(name).join_table.name}.#{opts[:score_column]} DESC") },
32
+ habtm_opts, &HasManyScored::HasManyScoredExtension.bind_extension(opts))
33
+ end
34
+
35
+ def scored_for_many(name, opts=nil)
36
+ opts = opts.try(:dup) || {}
37
+
38
+ habtm_opts = opts.select { |k, v| VALID_HABTM_OPTIONS.include?(k) }
39
+ habtm_opts[:insert_sql] = lambda { |record|
40
+ proxy_association = self.association(name)
41
+ join_table = proxy_association.join_table
42
+ reflection = proxy_association.reflection
43
+
44
+ return join_table.compile_insert(
45
+ join_table[reflection.foreign_key] => self.id,
46
+ join_table[reflection.association_foreign_key] => record.id,
47
+ join_table[opts[:score_column]] => proxy_association.scope.compute_score(self))
48
+ }
49
+
50
+ opts[:score_column] ||= :score
51
+ opts[:score_field] ||= :score
52
+
53
+ has_and_belongs_to_many(
54
+ name,
55
+ lambda { |owner| order("#{owner.association(name).join_table.name}.#{opts[:score_column]} DESC") },
56
+ habtm_opts, &HasManyScored::HasManyScoredExtension.bind_extension(opts))
57
+ end
58
+ end
59
+
60
+ def self.included(base)
61
+ base.extend(ClassMethods)
62
+ end
63
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'has_many_scored'
3
+
4
+ describe HasManyScored do
5
+ it "should have a VERSION constant" do
6
+ subject.const_get('VERSION').should_not be_empty
7
+ end
8
+ end
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+ require 'has_many_scored'
3
+
4
+ class Topic < ActiveRecord::Base
5
+ include HasManyScored
6
+ scored_for_many :tags
7
+ end
8
+ class Tag < ActiveRecord::Base
9
+ include HasManyScored
10
+ has_many_scored :topics
11
+ end
12
+
13
+ def setup_schema!
14
+ setup_db do
15
+ create_table :topics do |t|
16
+ t.column :name, :string
17
+ t.column :score, :float
18
+ end
19
+ create_table :tags do |t|
20
+ t.column :name, :string
21
+ end
22
+ create_table :tags_topics do |t|
23
+ t.column :topic_id, :integer
24
+ t.column :tag_id, :integer
25
+ t.column :score, :float
26
+ end
27
+ end
28
+ end
29
+
30
+ describe Tag do
31
+ before(:each) do
32
+ setup_schema!
33
+ end
34
+ after(:each) do
35
+ teardown_db
36
+ end
37
+ context "with dummy data" do
38
+ before do
39
+ @t1 = Topic.create(:name => "Topic 1", :score => 0.2)
40
+ @t2 = Topic.create(:name => "Topic 2", :score => 0.1)
41
+ @t3 = Topic.create(:name => "Topic 3", :score => 0.3)
42
+ @tag = Tag.create(:name => "Tag 1")
43
+ @tag.topics << @t1 << @t2 << @t3
44
+ end
45
+
46
+ it "computes size" do
47
+ expect(@tag.topics.size).to eq(3)
48
+ @tag.topics = []
49
+ expect(@tag.topics.size).to eq(0)
50
+ end
51
+
52
+ it "computes score when setting by ID" do
53
+ @tag.topic_ids = [@t1.id, @t2.id]
54
+ expect(@tag.topics(true).map(&:name)).to eq(["Topic 1", "Topic 2"])
55
+
56
+ @tag.topic_ids = [@t3.id]
57
+ expect(@tag.topics(true).map(&:name)).to eq(["Topic 3"])
58
+
59
+ @tag.topic_ids = [@t3.id, @t2.id, @t1.id]
60
+ expect(@tag.topics(true).map { |t| t.name }).to eq(["Topic 3", "Topic 1", "Topic 2"])
61
+ end
62
+
63
+ it "computes scores" do
64
+ expect(@tag.topics.compute_score(@t2)).to eq(0.1)
65
+ end
66
+
67
+ it "reads in scored order" do
68
+ # Sadly we have to call reload.
69
+ @tag.topics.reload
70
+
71
+ expect(@tag.topics.map { |t| t.name }).to eq(["Topic 3", "Topic 1", "Topic 2"])
72
+ expect(@tag.topics.first(2).map { |t| t.name }).to eq(["Topic 3", "Topic 1"])
73
+ end
74
+
75
+ it "handles delete" do
76
+ @tag.topics.delete(@t1)
77
+
78
+ expect(@tag.topics.map { |t| t.name }).to eq(["Topic 3", "Topic 2"])
79
+ end
80
+
81
+ it "handles update_score" do
82
+ @t2.score = 4.0
83
+ @t2.save
84
+ @tag.topics.update_score(@t2)
85
+
86
+ expect(Tag.first.topics.map { |t| t.name }).to eq(["Topic 2", "Topic 3", "Topic 1"])
87
+ end
88
+ end
89
+ end
90
+
91
+ describe Topic do
92
+ before(:each) do
93
+ setup_schema!
94
+ end
95
+ after(:each) do
96
+ teardown_db
97
+ end
98
+
99
+ context "with dummy data" do
100
+ before do
101
+ @t1 = Topic.create(:name => "Topic 1", :score => 0.2)
102
+ @t2 = Topic.create(:name => "Topic 2", :score => 0.1)
103
+ @t3 = Topic.create(:name => "Topic 3", :score => 0.3)
104
+ @tag1 = Tag.create(:name => "Tag 1")
105
+ @tag2 = Tag.create(:name => "Tag 2")
106
+ @tag2 = Tag.create(:name => "Tag 3")
107
+ @tag1.topics << @t2 << @t3
108
+ @t1.tags << @tag1 << @tag2
109
+ end
110
+
111
+ it "computes size" do
112
+ expect(@t1.tags.size).to eq(2)
113
+ @t1.tags = []
114
+ expect(@t1.tags.size).to eq(0)
115
+ end
116
+
117
+ it "reads in scored order" do
118
+ # Sadly we have to call reload.
119
+ @tag1.topics.reload
120
+
121
+ expect(@tag1.topics.map { |t| t.name }).to eq(["Topic 3", "Topic 1", "Topic 2"])
122
+ expect(@tag2.topics.map { |t| t.name }).to eq(["Topic 1"])
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,27 @@
1
+ gem "rspec", "~> 2.4"
2
+ require "rspec"
3
+ require "has_many_scored/version"
4
+
5
+ require "pry"
6
+ require "active_record"
7
+ require "fakeredis"
8
+ require "redis-objects"
9
+
10
+ include HasManyScored
11
+
12
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
13
+ ActiveRecord::Schema.verbose = false
14
+
15
+ def setup_db(&block)
16
+ # AR caches columns options like defaults etc. Clear them!
17
+ ActiveRecord::Base.connection.schema_cache.clear!
18
+ ActiveRecord::Schema.define(version: 1, &block)
19
+
20
+ Redis.current.flushall
21
+ end
22
+
23
+ def teardown_db
24
+ ActiveRecord::Base.connection.tables.each do |table|
25
+ ActiveRecord::Base.connection.drop_table(table)
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_many_scored
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Hsiu-Fan Wang
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-18 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: '3.0'
20
+ - - "<="
21
+ - !ruby/object:Gem::Version
22
+ version: 4.0.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - - "<="
31
+ - !ruby/object:Gem::Version
32
+ version: 4.0.2
33
+ - !ruby/object:Gem::Dependency
34
+ name: redis-objects
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.6.1
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.6.1
47
+ - !ruby/object:Gem::Dependency
48
+ name: pry
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: sqlite3
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: fakeredis
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rdoc
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 4.1.0
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 4.1.0
103
+ - !ruby/object:Gem::Dependency
104
+ name: rspec
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '2.4'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '2.4'
117
+ - !ruby/object:Gem::Dependency
118
+ name: rubygems-tasks
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '0.2'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '0.2'
131
+ description: An ActiveRecord plugin that combines an ordered habtm-like association
132
+ with optional redis caching.
133
+ email: hfwang@porkbuns.net
134
+ executables: []
135
+ extensions: []
136
+ extra_rdoc_files: []
137
+ files:
138
+ - ".gitignore"
139
+ - ".rspec"
140
+ - ChangeLog.rdoc
141
+ - Gemfile
142
+ - Gemfile.lock
143
+ - LICENSE
144
+ - README.md
145
+ - Rakefile
146
+ - has_many_scored.gemspec
147
+ - lib/has_many_scored.rb
148
+ - lib/has_many_scored/has_many_scored_extension.rb
149
+ - lib/has_many_scored/scored_for_many_extension.rb
150
+ - lib/has_many_scored/version.rb
151
+ - spec/has_many_scored_spec.rb
152
+ - spec/simple_model_spec.rb
153
+ - spec/spec_helper.rb
154
+ homepage: https://rubygems.org/gems/has_many_scored
155
+ licenses:
156
+ - MIT
157
+ metadata: {}
158
+ post_install_message:
159
+ rdoc_options: []
160
+ require_paths:
161
+ - lib
162
+ required_ruby_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ requirements: []
173
+ rubyforge_project:
174
+ rubygems_version: 2.2.1
175
+ signing_key:
176
+ specification_version: 4
177
+ summary: An ActiveRecord plugin that combines an ordered habtm-like association with
178
+ optional redis caching
179
+ test_files:
180
+ - spec/has_many_scored_spec.rb
181
+ - spec/simple_model_spec.rb
182
+ - spec/spec_helper.rb