nested_has_many_through 0.0.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.
- data/.gitignore +4 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +94 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +61 -0
- data/Rakefile +12 -0
- data/init.rb +2 -0
- data/lib/nested_has_many_through/association.rb +132 -0
- data/lib/nested_has_many_through/reflection.rb +14 -0
- data/lib/nested_has_many_through/version.rb +3 -0
- data/lib/nested_has_many_through.rb +15 -0
- data/nested_has_many_through.gemspec +32 -0
- data/spec/models/author_spec.rb +84 -0
- data/spec/models/commenter_spec.rb +108 -0
- data/spec/rails_app/.gitignore +4 -0
- data/spec/rails_app/Gemfile +31 -0
- data/spec/rails_app/Gemfile.lock +74 -0
- data/spec/rails_app/README +13 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/controllers/application_controller.rb +3 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/models/author.rb +8 -0
- data/spec/rails_app/app/models/category.rb +3 -0
- data/spec/rails_app/app/models/comment.rb +4 -0
- data/spec/rails_app/app/models/post.rb +17 -0
- data/spec/rails_app/app/models/user.rb +7 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_app/config/application.rb +42 -0
- data/spec/rails_app/config/boot.rb +6 -0
- data/spec/rails_app/config/database.yml +22 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +26 -0
- data/spec/rails_app/config/environments/production.rb +49 -0
- data/spec/rails_app/config/environments/test.rb +35 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/inflections.rb +10 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/initializers/session_store.rb +8 -0
- data/spec/rails_app/config/locales/en.yml +5 -0
- data/spec/rails_app/config/routes.rb +58 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/db/schema.rb +31 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/rails_app/script/delayed_job +5 -0
- data/spec/rails_app/script/gitr +14 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/spec_helper.rb +10 -0
- metadata +197 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
nested_has_many_through (0.0.1)
|
5
|
+
rails (>= 3.0.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
abstract (1.0.0)
|
11
|
+
actionmailer (3.0.6)
|
12
|
+
actionpack (= 3.0.6)
|
13
|
+
mail (~> 2.2.15)
|
14
|
+
actionpack (3.0.6)
|
15
|
+
activemodel (= 3.0.6)
|
16
|
+
activesupport (= 3.0.6)
|
17
|
+
builder (~> 2.1.2)
|
18
|
+
erubis (~> 2.6.6)
|
19
|
+
i18n (~> 0.5.0)
|
20
|
+
rack (~> 1.2.1)
|
21
|
+
rack-mount (~> 0.6.14)
|
22
|
+
rack-test (~> 0.5.7)
|
23
|
+
tzinfo (~> 0.3.23)
|
24
|
+
activemodel (3.0.6)
|
25
|
+
activesupport (= 3.0.6)
|
26
|
+
builder (~> 2.1.2)
|
27
|
+
i18n (~> 0.5.0)
|
28
|
+
activerecord (3.0.6)
|
29
|
+
activemodel (= 3.0.6)
|
30
|
+
activesupport (= 3.0.6)
|
31
|
+
arel (~> 2.0.2)
|
32
|
+
tzinfo (~> 0.3.23)
|
33
|
+
activeresource (3.0.6)
|
34
|
+
activemodel (= 3.0.6)
|
35
|
+
activesupport (= 3.0.6)
|
36
|
+
activesupport (3.0.6)
|
37
|
+
arel (2.0.9)
|
38
|
+
builder (2.1.2)
|
39
|
+
diff-lcs (1.1.2)
|
40
|
+
erubis (2.6.6)
|
41
|
+
abstract (>= 1.0.0)
|
42
|
+
i18n (0.5.0)
|
43
|
+
mail (2.2.15)
|
44
|
+
activesupport (>= 2.3.6)
|
45
|
+
i18n (>= 0.4.0)
|
46
|
+
mime-types (~> 1.16)
|
47
|
+
treetop (~> 1.4.8)
|
48
|
+
mime-types (1.16)
|
49
|
+
polyglot (0.3.1)
|
50
|
+
rack (1.2.2)
|
51
|
+
rack-mount (0.6.14)
|
52
|
+
rack (>= 1.0.0)
|
53
|
+
rack-test (0.5.7)
|
54
|
+
rack (>= 1.0)
|
55
|
+
rails (3.0.6)
|
56
|
+
actionmailer (= 3.0.6)
|
57
|
+
actionpack (= 3.0.6)
|
58
|
+
activerecord (= 3.0.6)
|
59
|
+
activeresource (= 3.0.6)
|
60
|
+
activesupport (= 3.0.6)
|
61
|
+
bundler (~> 1.0)
|
62
|
+
railties (= 3.0.6)
|
63
|
+
railties (3.0.6)
|
64
|
+
actionpack (= 3.0.6)
|
65
|
+
activesupport (= 3.0.6)
|
66
|
+
rake (>= 0.8.7)
|
67
|
+
thor (~> 0.14.4)
|
68
|
+
rake (0.8.7)
|
69
|
+
rspec (2.5.0)
|
70
|
+
rspec-core (~> 2.5.0)
|
71
|
+
rspec-expectations (~> 2.5.0)
|
72
|
+
rspec-mocks (~> 2.5.0)
|
73
|
+
rspec-core (2.5.1)
|
74
|
+
rspec-expectations (2.5.0)
|
75
|
+
diff-lcs (~> 1.1.2)
|
76
|
+
rspec-mocks (2.5.0)
|
77
|
+
sqlite3 (1.3.3)
|
78
|
+
sqlite3-ruby (1.3.3)
|
79
|
+
sqlite3 (>= 1.3.3)
|
80
|
+
thor (0.14.6)
|
81
|
+
treetop (1.4.9)
|
82
|
+
polyglot (>= 0.3.1)
|
83
|
+
tzinfo (0.3.26)
|
84
|
+
yard (0.6.7)
|
85
|
+
|
86
|
+
PLATFORMS
|
87
|
+
ruby
|
88
|
+
|
89
|
+
DEPENDENCIES
|
90
|
+
bundler (>= 1.0.0)
|
91
|
+
nested_has_many_through!
|
92
|
+
rspec (~> 2.5.0)
|
93
|
+
sqlite3-ruby
|
94
|
+
yard
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Ian White - ian.w.white@gmail.com
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
= NestedHasManyThrough
|
2
|
+
|
3
|
+
This gem makes it possible to define has_many :through relationships that
|
4
|
+
go through other has_many :through relationships, possibly through an
|
5
|
+
arbitrarily deep hierarchy. This allows associations across any number of
|
6
|
+
tables to be constructed, without having to resort to find_by_sql (which isn't
|
7
|
+
a suitable solution if you need to do eager loading through :include as well).
|
8
|
+
|
9
|
+
NOTE: Rails 3.x supports only. Rails 2.3 users might want to try the original nested_has_many_through[https://github.com/ianwhite/nested_has_many_through] plugin
|
10
|
+
|
11
|
+
== Intallation
|
12
|
+
|
13
|
+
Install the gem:
|
14
|
+
|
15
|
+
gem install nested_has_many_through
|
16
|
+
|
17
|
+
Add it to your gem file::
|
18
|
+
|
19
|
+
gem "nested_has_many_through"
|
20
|
+
|
21
|
+
== Usage
|
22
|
+
|
23
|
+
class Author < User
|
24
|
+
has_many :posts
|
25
|
+
has_many :categories, :through => :posts, :uniq => true
|
26
|
+
has_many :similar_posts, :through => :categories, :source => :posts
|
27
|
+
has_many :similar_authors, :through => :similar_posts, :source => :author, :uniq => true
|
28
|
+
has_many :posts_of_similar_authors, :through => :similar_authors, :source => :posts, :uniq => true
|
29
|
+
has_many :commenters, :through => :posts, :uniq => true
|
30
|
+
end
|
31
|
+
|
32
|
+
class Post < ActiveRecord::Base
|
33
|
+
belongs_to :author
|
34
|
+
belongs_to :category
|
35
|
+
has_many :comments
|
36
|
+
has_many :commenters, :through => :comments, :source => :user, :uniq => true
|
37
|
+
end
|
38
|
+
|
39
|
+
The first two has_manys of Author are plain vanilla, the last four are what this plugin enables
|
40
|
+
|
41
|
+
# has_many through a has_many :through
|
42
|
+
has_many :similar_posts, :through => :categories, :source => :posts
|
43
|
+
|
44
|
+
# doubly nested has_many :through
|
45
|
+
has_many :similar_authors, :through => :similar_posts, :source => :author, :uniq => true
|
46
|
+
|
47
|
+
# whoah!
|
48
|
+
has_many :posts_of_similar_authors, :through => :similar_authors, :source => :posts, :uniq => true
|
49
|
+
|
50
|
+
# has_many through a has_many :through in another model
|
51
|
+
has_many :commenters, :through => :posts, :uniq => true
|
52
|
+
|
53
|
+
== Maintainers
|
54
|
+
|
55
|
+
* Roman V. Babenko (http://github.com/romanvbabenko)
|
56
|
+
|
57
|
+
== Copyrights
|
58
|
+
|
59
|
+
This gem based on code nested_has_many_through[https://github.com/ianwhite/nested_has_many_through] plugin
|
60
|
+
|
61
|
+
MIT License. Copyright (c) 2008 Ian White - ian.w.white@gmail.com
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
desc 'Default: run tests for nested_has_many_through'
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
require 'rspec/core/rake_task'
|
10
|
+
RSpec::Core::RakeTask.new(:spec)
|
11
|
+
task :default => :spec
|
12
|
+
|
data/init.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
module NestedHasManyThrough
|
2
|
+
module Association
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
def construct_conditions
|
6
|
+
@nested_join_attributes ||= construct_nested_join_attributes
|
7
|
+
if @reflection.through_reflection && @reflection.through_reflection.macro == :belongs_to
|
8
|
+
"#{@nested_join_attributes[:remote_key]} = #{belongs_to_quoted_key} #{@nested_join_attributes[:conditions]}"
|
9
|
+
else
|
10
|
+
"#{@nested_join_attributes[:remote_key]} = #{@owner.quoted_id} #{@nested_join_attributes[:conditions]}"
|
11
|
+
end
|
12
|
+
"#{@nested_join_attributes[:remote_key]} = #{@owner.quoted_id} #{@nested_join_attributes[:conditions]}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def construct_joins(custom_joins = nil)
|
16
|
+
@nested_join_attributes ||= construct_nested_join_attributes
|
17
|
+
"#{@nested_join_attributes[:joins]} #{custom_joins}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
# Given any belongs_to or has_many (including has_many :through) association,
|
24
|
+
# return the essential components of a join corresponding to that association, namely:
|
25
|
+
#
|
26
|
+
# * <tt>:joins</tt>: any additional joins required to get from the association's table
|
27
|
+
# (reflection.table_name) to the table that's actually joining to the active record's table
|
28
|
+
# * <tt>:remote_key</tt>: the name of the key in the join table (qualified by table name) which will join
|
29
|
+
# to a field of the active record's table
|
30
|
+
# * <tt>:local_key</tt>: the name of the key in the local table (not qualified by table name) which will
|
31
|
+
# take part in the join
|
32
|
+
# * <tt>:conditions</tt>: any additional conditions (e.g. filtering by type for a polymorphic association,
|
33
|
+
# or a :conditions clause explicitly given in the association), including a leading AND
|
34
|
+
def construct_nested_join_attributes(reflection = @reflection, association_class = reflection.klass,
|
35
|
+
table_ids = {association_class.table_name => 1})
|
36
|
+
if reflection.macro == :has_many && reflection.through_reflection
|
37
|
+
construct_has_many_through_attributes(reflection, table_ids)
|
38
|
+
else
|
39
|
+
construct_has_many_or_belongs_to_attributes(reflection, association_class, table_ids)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def construct_has_many_through_attributes(reflection, table_ids)
|
44
|
+
# Construct the join components of the source association, so that we have a path from
|
45
|
+
# the eventual target table of the association up to the table named in :through, and
|
46
|
+
# all tables involved are allocated table IDs.
|
47
|
+
source_attrs = construct_nested_join_attributes(reflection.source_reflection, reflection.klass, table_ids)
|
48
|
+
|
49
|
+
# Determine the alias of the :through table; this will be the last table assigned
|
50
|
+
# when constructing the source join components above.
|
51
|
+
through_table_alias = through_table_name = reflection.through_reflection.table_name
|
52
|
+
through_table_alias += "_#{table_ids[through_table_name]}" unless table_ids[through_table_name] == 1
|
53
|
+
|
54
|
+
# Construct the join components of the through association, so that we have a path to
|
55
|
+
# the active record's table.
|
56
|
+
through_attrs = construct_nested_join_attributes(reflection.through_reflection, reflection.through_reflection.klass, table_ids)
|
57
|
+
|
58
|
+
# Any subsequent joins / filters on owner attributes will act on the through association,
|
59
|
+
# so that's what we return for the conditions/keys of the overall association.
|
60
|
+
conditions = through_attrs[:conditions]
|
61
|
+
conditions += " AND #{interpolate_sql(reflection.klass.send(:sanitize_sql, reflection.options[:conditions]))}" if reflection.options[:conditions]
|
62
|
+
|
63
|
+
{
|
64
|
+
:joins => "%s INNER JOIN %s ON ( %s = %s.%s %s) %s %s" % [
|
65
|
+
source_attrs[:joins],
|
66
|
+
through_table_name == through_table_alias ? through_table_name : "#{through_table_name} #{through_table_alias}",
|
67
|
+
source_attrs[:remote_key],
|
68
|
+
through_table_alias, source_attrs[:local_key],
|
69
|
+
source_attrs[:conditions],
|
70
|
+
through_attrs[:joins],
|
71
|
+
reflection.options[:joins]
|
72
|
+
],
|
73
|
+
:remote_key => through_attrs[:remote_key],
|
74
|
+
:local_key => through_attrs[:local_key],
|
75
|
+
:conditions => conditions
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
# reflection is not has_many :through; it's a standard has_many / belongs_to instead
|
80
|
+
# TODO: see if we can defer to rails code here a bit more
|
81
|
+
def construct_has_many_or_belongs_to_attributes(reflection, association_class, table_ids)
|
82
|
+
# Determine the alias used for remote_table_name, if any. In all cases this will already
|
83
|
+
# have been assigned an ID in table_ids (either through being involved in a previous join,
|
84
|
+
# or - if it's the first table in the query - as the default value of table_ids)
|
85
|
+
remote_table_alias = remote_table_name = association_class.table_name
|
86
|
+
remote_table_alias += "_#{table_ids[remote_table_name]}" unless table_ids[remote_table_name] == 1
|
87
|
+
|
88
|
+
# Assign a new alias for the local table.
|
89
|
+
local_table_alias = local_table_name = reflection.active_record.table_name
|
90
|
+
if table_ids[local_table_name]
|
91
|
+
table_id = table_ids[local_table_name] += 1
|
92
|
+
local_table_alias += "_#{table_id}"
|
93
|
+
else
|
94
|
+
table_ids[local_table_name] = 1
|
95
|
+
end
|
96
|
+
|
97
|
+
conditions = ''
|
98
|
+
# Add type_condition, if applicable
|
99
|
+
conditions += " AND #{association_class.send(:type_condition).to_sql}" if association_class.finder_needs_type_condition?
|
100
|
+
# Add custom conditions
|
101
|
+
conditions += " AND (#{interpolate_sql(association_class.send(:sanitize_sql, reflection.options[:conditions]))})" if reflection.options[:conditions]
|
102
|
+
|
103
|
+
if reflection.macro == :belongs_to
|
104
|
+
if reflection.options[:polymorphic]
|
105
|
+
conditions += " AND #{local_table_alias}.#{reflection.options[:foreign_type]} = #{reflection.active_record.quote_value(association_class.base_class.name.to_s)}"
|
106
|
+
end
|
107
|
+
{
|
108
|
+
:joins => reflection.options[:joins],
|
109
|
+
:remote_key => "#{remote_table_alias}.#{association_class.primary_key}",
|
110
|
+
:local_key => reflection.primary_key_name,
|
111
|
+
:conditions => conditions
|
112
|
+
}
|
113
|
+
else
|
114
|
+
# Association is has_many (without :through)
|
115
|
+
if reflection.options[:as]
|
116
|
+
conditions += " AND #{remote_table_alias}.#{reflection.options[:as]}_type = #{reflection.active_record.quote_value(reflection.active_record.base_class.name.to_s)}"
|
117
|
+
end
|
118
|
+
{
|
119
|
+
:joins => "#{reflection.options[:joins]}",
|
120
|
+
:remote_key => "#{remote_table_alias}.#{reflection.primary_key_name}",
|
121
|
+
:local_key => reflection.klass.primary_key,
|
122
|
+
:conditions => conditions
|
123
|
+
}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def belongs_to_quoted_key
|
129
|
+
attribute, col = @reflection.through_reflection.primary_key_name, @owner.column_for_attribute(attribute)
|
130
|
+
@owner.send(:quote_value, @owner.send(attribute), col)
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module NestedHasManyThrough
|
2
|
+
module Reflection # :nodoc:
|
3
|
+
def self.included(base)
|
4
|
+
base.send :alias_method_chain, :check_validity!, :nested_has_many_through
|
5
|
+
end
|
6
|
+
|
7
|
+
def check_validity_with_nested_has_many_through!
|
8
|
+
check_validity_without_nested_has_many_through!
|
9
|
+
rescue ActiveRecord::HasManyThroughSourceAssociationMacroError => e
|
10
|
+
# now we permit has many through to a :though source
|
11
|
+
raise e unless source_reflection.options[:through]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "nested_has_many_through/association"
|
2
|
+
require "nested_has_many_through/reflection"
|
3
|
+
|
4
|
+
module NestedHasManyThrough
|
5
|
+
autoload :Association, 'nested_has_many_through/association'
|
6
|
+
autoload :Reflection, 'nested_has_many_through/reflection'
|
7
|
+
end
|
8
|
+
|
9
|
+
ActiveRecord::Associations::HasManyThroughAssociation.send :include, NestedHasManyThrough::Association
|
10
|
+
|
11
|
+
if defined?(ActiveRecord::Reflection::ThroughReflection)
|
12
|
+
ActiveRecord::Reflection::ThroughReflection.send :include, NestedHasManyThrough::Reflection
|
13
|
+
else
|
14
|
+
ActiveRecord::Reflection::AssociationReflection.send :include, NestedHasManyThrough::Reflection
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "nested_has_many_through/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "nested_has_many_through"
|
7
|
+
s.version = NestedHasManyThrough::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Ian White"]
|
10
|
+
s.email = ["ian.w.white@gmail.com"]
|
11
|
+
s.homepage = "http://twitter.com/i2w"
|
12
|
+
s.summary = %q{Rails gem that allows has_many :through to go through other has_many :throughs}
|
13
|
+
s.description = %q{This plugin makes it possible to define has_many :through relationships that
|
14
|
+
go through other has_many :through relationships, possibly through an arbitrarily deep hierarchy.
|
15
|
+
This allows associations across any number of tables to be constructed, without having to resort to
|
16
|
+
find_by_sql (which isn't a suitable solution if you need to do eager loading through :include as well).}
|
17
|
+
|
18
|
+
s.rubyforge_project = "nested_has_many_through"
|
19
|
+
|
20
|
+
s.add_dependency "rails", ">= 3.0.0"
|
21
|
+
|
22
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
23
|
+
s.add_development_dependency "rspec", "~> 2.5.0"
|
24
|
+
s.add_development_dependency "yard"
|
25
|
+
s.add_development_dependency "sqlite3-ruby"
|
26
|
+
|
27
|
+
s.files = `git ls-files`.split("\n")
|
28
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
29
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
30
|
+
s.require_paths = ["lib"]
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Author do
|
4
|
+
describe "(newly created)" do
|
5
|
+
before do
|
6
|
+
@category = Category.create!
|
7
|
+
@other_category = Category.create!
|
8
|
+
@author = Author.create!
|
9
|
+
end
|
10
|
+
|
11
|
+
it "#posts should == []" do
|
12
|
+
@author.posts.should == []
|
13
|
+
end
|
14
|
+
|
15
|
+
it "#categories should == []" do
|
16
|
+
@author.categories.should == []
|
17
|
+
end
|
18
|
+
|
19
|
+
it "#similar_posts should == []" do
|
20
|
+
@author.similar_posts.should be_empty
|
21
|
+
end
|
22
|
+
|
23
|
+
it "#similar_authors should == []" do
|
24
|
+
@author.similar_authors.should be_empty
|
25
|
+
end
|
26
|
+
|
27
|
+
it "#commenters should == []" do
|
28
|
+
@author.commenters.should == []
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "who creates post with category" do
|
32
|
+
before do
|
33
|
+
@post = Post.create! :author => @author, :category => @category
|
34
|
+
end
|
35
|
+
|
36
|
+
it "#posts should == [post]" do
|
37
|
+
@author.posts.should == [@post]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "#categories should == [category]" do
|
41
|
+
@author.categories.should == [@category]
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "and @other_author creates post2 in category" do
|
45
|
+
|
46
|
+
before do
|
47
|
+
@other_author = Author.create!
|
48
|
+
@post2 = Post.create! :author => @other_author, :category => @category
|
49
|
+
end
|
50
|
+
|
51
|
+
it "#posts should == [post2]" do
|
52
|
+
@author.posts.should == [@post]
|
53
|
+
end
|
54
|
+
|
55
|
+
it "#categories should == [category]" do
|
56
|
+
@author.categories.should == [@category]
|
57
|
+
end
|
58
|
+
|
59
|
+
it "#similar_posts.should == [post, post2]" do
|
60
|
+
@author.similar_posts.should == [@post, @post2]
|
61
|
+
end
|
62
|
+
|
63
|
+
it "#similar_authors.should == [@author, @other_author]" do
|
64
|
+
@author.similar_authors.should == [@author, @other_author]
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "and creates @other_post in @other_category" do
|
68
|
+
before do
|
69
|
+
@other_category = Category.create!
|
70
|
+
@other_post = Post.create! :author => @other_author, :category => @other_category
|
71
|
+
end
|
72
|
+
|
73
|
+
it "#similar_posts.should == [@post, @post2]" do
|
74
|
+
@author.similar_posts.should == [@post, @post2]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "#posts_by_similar_authors.should == [@post, @post2, @other_post]" do
|
78
|
+
@author.posts_of_similar_authors.should == [@post, @post2, @other_post]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe 'Commenter use case (a1: p1>c1, a2: p2>c1, p3>c2, a3: p4>c3)' do
|
4
|
+
before do
|
5
|
+
@c1 = Category.create!
|
6
|
+
@c2 = Category.create!
|
7
|
+
@c3 = Category.create!
|
8
|
+
@a1 = Author.create!
|
9
|
+
@a2 = Author.create!
|
10
|
+
@a3 = Author.create!
|
11
|
+
@p1 = @a1.posts.create! :category => @c1
|
12
|
+
@p2 = @a2.posts.create! :category => @c1
|
13
|
+
@p3 = @a2.posts.create! :category => @c2
|
14
|
+
@p4 = @a3.posts.create! :category => @c3
|
15
|
+
@a1.reload
|
16
|
+
@a2.reload
|
17
|
+
end
|
18
|
+
|
19
|
+
it "a1.posts should == [p1]" do
|
20
|
+
@a1.posts.should == [@p1]
|
21
|
+
end
|
22
|
+
|
23
|
+
it "a1.categories should == [c1]" do
|
24
|
+
@a1.categories.should == [@c1]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "a2.posts should == [p2, p3]" do
|
28
|
+
@a2.posts.should == [@p2, @p3]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "a2.categories should == [c1, c2]" do
|
32
|
+
@a2.categories.should == [@c1, @c2]
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "u1 comments on p2" do
|
36
|
+
before do
|
37
|
+
@u1 = User.create!
|
38
|
+
@comment = @p2.comments.create! :user => @u1
|
39
|
+
end
|
40
|
+
|
41
|
+
it "u1.comments should == [comment]" do
|
42
|
+
@u1.comments.should == [@comment]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "a1.commenters should be empty" do
|
46
|
+
@a1.commenters.should be_empty
|
47
|
+
end
|
48
|
+
|
49
|
+
it "a2.commenters should == [u1]" do
|
50
|
+
@a2.commenters.should == [@u1]
|
51
|
+
end
|
52
|
+
|
53
|
+
it "u1.commented_posts should == [p2]" do
|
54
|
+
@u1.commented_posts.should == [@p2]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "u1.commented_posts.find_inflamatory(:all) should be empty" do
|
58
|
+
@u1.commented_posts.find_inflamatory(:all).should be_empty
|
59
|
+
end
|
60
|
+
|
61
|
+
if ActiveRecord::Base.respond_to?(:named_scope)
|
62
|
+
it "u1.commented_posts.inflamatory should be empty" do
|
63
|
+
@u1.commented_posts.inflamatory.should be_empty
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "u1.commented_authors should == [a2]" do
|
68
|
+
@u1.commented_authors.should == [@a2]
|
69
|
+
end
|
70
|
+
|
71
|
+
it "u1.posts_of_interest should == [p1, p2, p3]" do
|
72
|
+
@u1.posts_of_interest.should == [@p1, @p2, @p3]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "u1.categories_of_interest should == [c1, c2]" do
|
76
|
+
@u1.categories_of_interest.should == [@c1, @c2]
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "when p2 is inflamatory" do
|
80
|
+
before do
|
81
|
+
@p2.toggle!(:inflamatory)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "p2 should be inflamatory" do
|
85
|
+
@p2.should be_inflamatory
|
86
|
+
end
|
87
|
+
|
88
|
+
it "u1.commented_posts.find_inflamatory(:all) should == [p2]" do
|
89
|
+
# uniq ids is here (and next spec) because eager loading changed behaviour 2.0.2 => edge
|
90
|
+
@u1.commented_posts.find_inflamatory(:all).collect(&:id).uniq.should == [@p2.id]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "u1.posts_of_interest.find_inflamatory(:all).uniq should == [p2]" do
|
94
|
+
@u1.posts_of_interest.find_inflamatory(:all).collect(&:id).uniq.should == [@p2.id]
|
95
|
+
end
|
96
|
+
|
97
|
+
if ActiveRecord::Base.respond_to?(:named_scope)
|
98
|
+
it "u1.commented_posts.inflamatory should == [p2]" do
|
99
|
+
@u1.commented_posts.inflamatory.should == [@p2]
|
100
|
+
end
|
101
|
+
|
102
|
+
it "u1.posts_of_interest.inflamatory should == [p2]" do
|
103
|
+
@u1.posts_of_interest.inflamatory.should == [@p2]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
gem 'rails', '3.0.0'
|
4
|
+
|
5
|
+
# Bundle edge Rails instead:
|
6
|
+
# gem 'rails', :git => 'git://github.com/rails/rails.git'
|
7
|
+
|
8
|
+
gem 'sqlite3'
|
9
|
+
|
10
|
+
# Use unicorn as the web server
|
11
|
+
# gem 'unicorn'
|
12
|
+
|
13
|
+
# Deploy with Capistrano
|
14
|
+
# gem 'capistrano'
|
15
|
+
|
16
|
+
# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
|
17
|
+
# gem 'ruby-debug'
|
18
|
+
# gem 'ruby-debug19', :require => 'ruby-debug'
|
19
|
+
|
20
|
+
# Bundle the extra gems:
|
21
|
+
# gem 'bj'
|
22
|
+
# gem 'nokogiri'
|
23
|
+
# gem 'sqlite3-ruby', :require => 'sqlite3'
|
24
|
+
# gem 'aws-s3', :require => 'aws/s3'
|
25
|
+
|
26
|
+
# Bundle gems for the local environment. Make sure to
|
27
|
+
# put test-only gems in this group so their generators
|
28
|
+
# and rake tasks are available in development mode:
|
29
|
+
# group :development, :test do
|
30
|
+
# gem 'webrat'
|
31
|
+
# end
|