archive_tree 1.0.0.rc3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +19 -0
- data/Gemfile.lock +109 -0
- data/README.md +19 -5
- data/Rakefile +38 -0
- data/lib/archive_tree.rb +1 -3
- data/lib/archive_tree/action_view_extensions.rb +67 -2
- data/spec/db/models.rb +3 -0
- data/spec/db/schema.rb +14 -0
- data/spec/factories/posts_factory.rb +6 -0
- data/spec/lib/action_view_extensions/action_view_extensions_spec.rb +76 -0
- data/spec/lib/archive_node_spec.rb +38 -0
- data/spec/lib/archive_tree_core_spec.rb +14 -0
- data/spec/lib/archive_tree_spec.rb +98 -0
- data/spec/lib/archived_months_spec.rb +49 -0
- data/spec/lib/archived_years_spec.rb +27 -0
- data/spec/spec_helper.rb +69 -0
- metadata +91 -15
- data/lib/archive_tree/action_view_extensions/draw_archive_tree.rb +0 -76
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source 'http://rubygems.org'
|
2
|
+
|
3
|
+
gem 'activerecord', '~> 3.0.1'
|
4
|
+
gem 'actionpack', '~> 3.0.1'
|
5
|
+
|
6
|
+
group :development, :test do
|
7
|
+
gem 'mysql', '~> 2.8.0'
|
8
|
+
|
9
|
+
if RUBY_VERSION =~ /1\.9\.\d/
|
10
|
+
gem('ruby-debug-base19', '=0.11.23') if RUBY_VERSION == '1.9.1'
|
11
|
+
gem 'ruby-debug19', '~> 0.11.0'
|
12
|
+
else
|
13
|
+
gem 'ruby-debug'
|
14
|
+
end
|
15
|
+
|
16
|
+
gem 'rspec', '~> 2.0.0'
|
17
|
+
gem 'factory_girl_rails', '~> 1.0.0'
|
18
|
+
gem 'database_cleaner', '~> 0.6.0'
|
19
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
abstract (1.0.0)
|
5
|
+
actionmailer (3.0.1)
|
6
|
+
actionpack (= 3.0.1)
|
7
|
+
mail (~> 2.2.5)
|
8
|
+
actionpack (3.0.1)
|
9
|
+
activemodel (= 3.0.1)
|
10
|
+
activesupport (= 3.0.1)
|
11
|
+
builder (~> 2.1.2)
|
12
|
+
erubis (~> 2.6.6)
|
13
|
+
i18n (~> 0.4.1)
|
14
|
+
rack (~> 1.2.1)
|
15
|
+
rack-mount (~> 0.6.12)
|
16
|
+
rack-test (~> 0.5.4)
|
17
|
+
tzinfo (~> 0.3.23)
|
18
|
+
activemodel (3.0.1)
|
19
|
+
activesupport (= 3.0.1)
|
20
|
+
builder (~> 2.1.2)
|
21
|
+
i18n (~> 0.4.1)
|
22
|
+
activerecord (3.0.1)
|
23
|
+
activemodel (= 3.0.1)
|
24
|
+
activesupport (= 3.0.1)
|
25
|
+
arel (~> 1.0.0)
|
26
|
+
tzinfo (~> 0.3.23)
|
27
|
+
activeresource (3.0.1)
|
28
|
+
activemodel (= 3.0.1)
|
29
|
+
activesupport (= 3.0.1)
|
30
|
+
activesupport (3.0.1)
|
31
|
+
archive-tar-minitar (0.5.2)
|
32
|
+
arel (1.0.1)
|
33
|
+
activesupport (~> 3.0.0)
|
34
|
+
builder (2.1.2)
|
35
|
+
columnize (0.3.2)
|
36
|
+
database_cleaner (0.6.0)
|
37
|
+
diff-lcs (1.1.2)
|
38
|
+
erubis (2.6.6)
|
39
|
+
abstract (>= 1.0.0)
|
40
|
+
factory_girl (1.3.2)
|
41
|
+
factory_girl_rails (1.0)
|
42
|
+
factory_girl (~> 1.3)
|
43
|
+
rails (>= 3.0.0.beta4)
|
44
|
+
i18n (0.4.2)
|
45
|
+
linecache19 (0.5.11)
|
46
|
+
ruby_core_source (>= 0.1.4)
|
47
|
+
mail (2.2.9)
|
48
|
+
activesupport (>= 2.3.6)
|
49
|
+
i18n (~> 0.4.1)
|
50
|
+
mime-types (~> 1.16)
|
51
|
+
treetop (~> 1.4.8)
|
52
|
+
mime-types (1.16)
|
53
|
+
mysql (2.8.1)
|
54
|
+
polyglot (0.3.1)
|
55
|
+
rack (1.2.1)
|
56
|
+
rack-mount (0.6.13)
|
57
|
+
rack (>= 1.0.0)
|
58
|
+
rack-test (0.5.6)
|
59
|
+
rack (>= 1.0)
|
60
|
+
rails (3.0.1)
|
61
|
+
actionmailer (= 3.0.1)
|
62
|
+
actionpack (= 3.0.1)
|
63
|
+
activerecord (= 3.0.1)
|
64
|
+
activeresource (= 3.0.1)
|
65
|
+
activesupport (= 3.0.1)
|
66
|
+
bundler (~> 1.0.0)
|
67
|
+
railties (= 3.0.1)
|
68
|
+
railties (3.0.1)
|
69
|
+
actionpack (= 3.0.1)
|
70
|
+
activesupport (= 3.0.1)
|
71
|
+
rake (>= 0.8.4)
|
72
|
+
thor (~> 0.14.0)
|
73
|
+
rake (0.8.7)
|
74
|
+
rspec (2.0.1)
|
75
|
+
rspec-core (~> 2.0.1)
|
76
|
+
rspec-expectations (~> 2.0.1)
|
77
|
+
rspec-mocks (~> 2.0.1)
|
78
|
+
rspec-core (2.0.1)
|
79
|
+
rspec-expectations (2.0.1)
|
80
|
+
diff-lcs (>= 1.1.2)
|
81
|
+
rspec-mocks (2.0.1)
|
82
|
+
rspec-core (~> 2.0.1)
|
83
|
+
rspec-expectations (~> 2.0.1)
|
84
|
+
ruby-debug-base19 (0.11.24)
|
85
|
+
columnize (>= 0.3.1)
|
86
|
+
linecache19 (>= 0.5.11)
|
87
|
+
ruby_core_source (>= 0.1.4)
|
88
|
+
ruby-debug19 (0.11.6)
|
89
|
+
columnize (>= 0.3.1)
|
90
|
+
linecache19 (>= 0.5.11)
|
91
|
+
ruby-debug-base19 (>= 0.11.19)
|
92
|
+
ruby_core_source (0.1.4)
|
93
|
+
archive-tar-minitar (>= 0.5.2)
|
94
|
+
thor (0.14.4)
|
95
|
+
treetop (1.4.8)
|
96
|
+
polyglot (>= 0.3.1)
|
97
|
+
tzinfo (0.3.23)
|
98
|
+
|
99
|
+
PLATFORMS
|
100
|
+
ruby
|
101
|
+
|
102
|
+
DEPENDENCIES
|
103
|
+
actionpack (~> 3.0.1)
|
104
|
+
activerecord (~> 3.0.1)
|
105
|
+
database_cleaner (~> 0.6.0)
|
106
|
+
factory_girl_rails (~> 1.0.0)
|
107
|
+
mysql (~> 2.8.0)
|
108
|
+
rspec (~> 2.0.0)
|
109
|
+
ruby-debug19 (~> 0.11.0)
|
data/README.md
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
## Introduction
|
2
2
|
|
3
|
-
ArchiveTree is a
|
3
|
+
ArchiveTree is a Ruby Gem for your Ruby on Rails application that makes it easy for you to generate structured trees of your records.
|
4
4
|
|
5
|
-
Since it
|
5
|
+
Since it uses a column of your choice, from any ActiveRecord Model, you will have flexibility to use in most of the Ruby on Rails applications
|
6
6
|
|
7
|
+
## Compatibility
|
8
|
+
|
9
|
+
The Gem was developed to work with Rails 3.0.x, running on Ruby 1.8.7 or 1.9.2.
|
10
|
+
Since it uses SQL specific queries, it works on MySQL and PostgreSQL databases.
|
11
|
+
|
12
|
+
**Note:** This gem does not work with Ruby v1.9.1.
|
7
13
|
|
8
14
|
## Installation
|
9
15
|
|
@@ -28,6 +34,14 @@ Now let's say that you wish to allow your users to sweep through your posts in a
|
|
28
34
|
|
29
35
|
### API
|
30
36
|
|
37
|
+
#### Inclusion:
|
38
|
+
|
39
|
+
In your ActiveRecord Model:
|
40
|
+
|
41
|
+
<pre>
|
42
|
+
acts_as_archive #=> defaults to :created_at
|
43
|
+
</pre>
|
44
|
+
|
31
45
|
#### Default usage:
|
32
46
|
|
33
47
|
<pre>
|
@@ -54,15 +68,15 @@ Post.archive_tree(:months => [1]) #=> { 2010 => { 1 => [Post] },
|
|
54
68
|
Post.archive_tree(:years_and_months => { 2010 => [1] }) #=> { 2010 => { 1 => [Post] } }
|
55
69
|
</pre>
|
56
70
|
|
57
|
-
###
|
71
|
+
### View
|
58
72
|
|
59
73
|
<pre>
|
60
|
-
draw_archive_tree
|
74
|
+
draw_archive_tree #=> defaults to: :model_sym => :post, :route => :posts_path, :toggle => true, :toggle_text => '[ + ]'
|
61
75
|
</pre>
|
62
76
|
|
63
77
|
## Documentation
|
64
78
|
|
65
|
-
This gem's documentation documentation is available at http://
|
79
|
+
This gem's documentation documentation is available at http://rubydoc.info/github/GnomesLab/archive_tree/
|
66
80
|
|
67
81
|
|
68
82
|
## License
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
desc 'Generate documentation for the archive_tree plugin.'
|
6
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
7
|
+
rdoc.rdoc_dir = 'rdoc'
|
8
|
+
rdoc.title = 'ArchiveTree'
|
9
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
10
|
+
rdoc.rdoc_files.include('README.md')
|
11
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
12
|
+
end
|
13
|
+
|
14
|
+
begin
|
15
|
+
require 'rspec/core/rake_task'
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
18
|
+
t.ruby_opts = '-w'
|
19
|
+
end
|
20
|
+
|
21
|
+
task :default => :spec
|
22
|
+
rescue LoadError
|
23
|
+
raise 'RSpec could not be loaded. Run `bundle install` to get all development dependencies.'
|
24
|
+
end
|
25
|
+
|
26
|
+
# Rubygems
|
27
|
+
namespace :rubygems do
|
28
|
+
gemspec = eval(File.read('archive_tree.gemspec'))
|
29
|
+
Rake::GemPackageTask.new(gemspec) do |pkg|
|
30
|
+
pkg.gem_spec = gemspec
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "build the gem and release it to rubygems.org"
|
34
|
+
task :release => :gem do
|
35
|
+
sh "rake spec"
|
36
|
+
sh "gem push pkg/archive_tree-#{gemspec.version}.gem"
|
37
|
+
end
|
38
|
+
end
|
data/lib/archive_tree.rb
CHANGED
@@ -17,8 +17,8 @@
|
|
17
17
|
# TODO: This module should undergo a query optimization. Furthermore, an ORM abstraction.
|
18
18
|
module ArchiveTree
|
19
19
|
|
20
|
-
require 'archive_tree/action_view_extensions'
|
21
20
|
autoload :Core, 'archive_tree/core'
|
21
|
+
autoload :ActionViewExtensions, 'archive_tree/action_view_extensions'
|
22
22
|
|
23
23
|
def acts_as_archive(date_field = :created_at)
|
24
24
|
raise ::ArgumentError, "undefined parameter #{date_field.to_s}" unless column = columns_hash[date_field.to_s]
|
@@ -33,5 +33,3 @@ module ArchiveTree
|
|
33
33
|
attr_accessor :date_field
|
34
34
|
|
35
35
|
end # ArchiveTree
|
36
|
-
|
37
|
-
ActiveRecord::Base.send :extend, ArchiveTree if defined?(ActiveRecord::Base)
|
@@ -1,8 +1,73 @@
|
|
1
1
|
module ArchiveTree
|
2
2
|
|
3
3
|
module ActionViewExtensions
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
# In the presence of records for a given model it draws the archive tree. Otherwise, returns an empty string
|
6
|
+
#
|
7
|
+
# This method relies on the following private methods:
|
8
|
+
# * +draw_years+
|
9
|
+
# * +draw_months+
|
10
|
+
#
|
11
|
+
# Default behavior
|
12
|
+
# * It will attempt to create a tree of your Post model
|
13
|
+
# * Will use the posts_path route
|
14
|
+
# * Will display a toggle link
|
15
|
+
# * Will use "[ + ]" as the text for the toggle link
|
16
|
+
#
|
17
|
+
# Options
|
18
|
+
# * model_sym #=> the symbol of the model to request the archive_nodes
|
19
|
+
# * route #=> the route that handles the archived posts requests
|
20
|
+
# * toggle #=> when true, includes a toggle link before the years
|
21
|
+
# * toggle_text #=> the text used in the toggle link
|
22
|
+
#
|
23
|
+
# Example using the default settings:
|
24
|
+
# <%= draw_archive_tree %>
|
25
|
+
#
|
26
|
+
# Overriding the defaults example:
|
27
|
+
# <%= draw_archive_tree :model_sym => :post, :route => :archive_published_at_path, :toggle => false %>
|
28
|
+
|
29
|
+
def draw_archive_tree(options = {})
|
30
|
+
options.reverse_merge!({ :model_sym => :post, :route => :posts_path, :toggle => true, :toggle_text => '[ + ]' })
|
31
|
+
model = options[:model_sym].to_s.capitalize.constantize
|
32
|
+
|
33
|
+
raw model.count > 0 ? draw_years(model, options[:route], options[:toggle], options[:toggle_text]) : ''
|
34
|
+
end # draw_archive_tree
|
35
|
+
|
36
|
+
private
|
37
|
+
def draw_years(model_sym, route, toggle, toggle_text) # :nodoc:
|
38
|
+
model = model_sym.to_s.capitalize.constantize
|
39
|
+
route = :posts_path unless self.respond_to? route
|
40
|
+
|
41
|
+
content_tag :ul do
|
42
|
+
ul_body = ""
|
43
|
+
|
44
|
+
model.archived_years.each_key do |year, count|
|
45
|
+
ul_body << content_tag(:li, :class => year == Time.now.year ? 'active' : 'inactive') do
|
46
|
+
(toggle ? link_to(toggle_text, "#", :class => "toggle") : '') + " " +
|
47
|
+
link_to(year, self.send(route, year)) +
|
48
|
+
draw_months(model_sym, route, year)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
ul_body
|
53
|
+
end
|
54
|
+
end # draw_years
|
55
|
+
|
56
|
+
def draw_months(model_sym, route, year) # :nodoc:
|
57
|
+
model = model_sym.to_s.capitalize.constantize
|
58
|
+
|
59
|
+
content_tag :ul do
|
60
|
+
ul_body = ""
|
61
|
+
|
62
|
+
model.archived_months(:year => year).each_pair do |month, count|
|
63
|
+
ul_body << content_tag(:li, link_to("#{Date::MONTHNAMES[month]} (#{count})",
|
64
|
+
self.send(route, year, month < 10 ? "0#{month}" : month)))
|
65
|
+
end
|
66
|
+
|
67
|
+
ul_body
|
68
|
+
end
|
69
|
+
end # draw_months
|
70
|
+
|
6
71
|
end # ActionViewExtensions
|
7
72
|
|
8
73
|
end # ArchiveTree
|
data/spec/db/models.rb
ADDED
data/spec/db/schema.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 20100803160738) do
|
2
|
+
|
3
|
+
create_table "posts", :force => true do |t|
|
4
|
+
t.string "title", :null => false
|
5
|
+
t.text "body", :null => false
|
6
|
+
t.datetime "published_at", :null => true
|
7
|
+
t.datetime "created_at"
|
8
|
+
t.datetime "updated_at"
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index "posts", ["created_at"], :name => "index_posts_on_created_at"
|
12
|
+
add_index "posts", ["published_at"], :name => "index_posts_on_published_at"
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
Factory.define(:post) do |p|
|
2
|
+
p.sequence(:title) { |n| "Post Title #{n}" }
|
3
|
+
p.sequence(:body) { |n| "This is the #{n}th post. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer dictum, neque ut imperdiet pellentesque, nulla tellus tempus magna, sed consectetur orci metus a justo. Aliquam ac congue nunc. Mauris a tortor ut massa egestas tempus. Pellentesque tincidunt fermentum diam sagittis ullamcorper. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer dictum." }
|
4
|
+
p.sequence(:published_at) { |n| Time.now - n.month }
|
5
|
+
p.created_at Time.now
|
6
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ArchiveTree::ActionViewExtensions do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@helper = ActionView::Base.new
|
7
|
+
|
8
|
+
# Inject routes into ActionView::Base
|
9
|
+
@helper.instance_eval do
|
10
|
+
def posts_path(*)
|
11
|
+
'/blog/2010'
|
12
|
+
end
|
13
|
+
|
14
|
+
def dummy_path(*)
|
15
|
+
'/dummy/2010'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "draw_achive_tree" do
|
21
|
+
|
22
|
+
it "should be included in ActionView::Base" do
|
23
|
+
@helper.should respond_to :draw_archive_tree
|
24
|
+
end # included
|
25
|
+
|
26
|
+
describe "without posts" do
|
27
|
+
it "returns an empty string when the archive tree is empty" do
|
28
|
+
@helper.draw_archive_tree.should be_empty
|
29
|
+
end
|
30
|
+
end # without posts
|
31
|
+
|
32
|
+
describe "with posts" do
|
33
|
+
before :each do
|
34
|
+
Factory.create :post, :created_at => Date.new(Time.now.year, 1, 1)
|
35
|
+
Factory.create :post, :created_at => Date.new(Time.now.year, 2, 1)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return the archive tree for all records" do
|
39
|
+
@helper.draw_archive_tree.should == %Q{<ul><li class=\"active\"><a href=\"#\" class=\"toggle\">[ + ]</a> <a href=\"/blog/2010\">2010</a><ul><li><a href=\"/blog/2010\">January (1)</a></li><li><a href=\"/blog/2010\">February (1)</a></li></ul></li></ul>}
|
40
|
+
end
|
41
|
+
end # with posts
|
42
|
+
|
43
|
+
describe "overridable" do
|
44
|
+
before :each do
|
45
|
+
Factory.create :post, :created_at => Date.new(Time.now.year, 1, 1)
|
46
|
+
Factory.create :post, :created_at => Date.new(Time.now.year, 2, 1)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "allows the model name to be overriden" do
|
50
|
+
lambda { @helper.draw_archive_tree(:model_sym => :hello) }.should raise_error NameError
|
51
|
+
end
|
52
|
+
|
53
|
+
it "allows the route to be overriden" do
|
54
|
+
@helper.draw_archive_tree(:route => :dummy_path).should == %Q{<ul><li class=\"active\"><a href=\"#\" class=\"toggle\">[ + ]</a> <a href=\"/dummy/2010\">2010</a><ul><li><a href=\"/dummy/2010\">January (1)</a></li><li><a href=\"/dummy/2010\">February (1)</a></li></ul></li></ul>}
|
55
|
+
end
|
56
|
+
|
57
|
+
it "defaults to the hardcoded route whenever the provided route is unknown" do
|
58
|
+
1.upto(10) { |i| Factory.create :post }
|
59
|
+
@helper.draw_archive_tree(:route => :xpto_path).should match(/ul/)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "allows the toggle to be overriden" do
|
63
|
+
html = @helper.draw_archive_tree(:toggle => false)
|
64
|
+
html.should_not include '<a href="#" class="toggle">[ + ]</a>'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "allows the toggle text to be overriden" do
|
68
|
+
html = @helper.draw_archive_tree(:toggle_text => '+toggle+')
|
69
|
+
html.should include '<a href="#" class="toggle">+toggle+</a>'
|
70
|
+
end
|
71
|
+
|
72
|
+
end # overridable
|
73
|
+
|
74
|
+
end # draw_achive_tree
|
75
|
+
|
76
|
+
end # ArchiveTree::ActionViewExtensions
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ArchiveTree do
|
4
|
+
describe "archive_node" do
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
1.upto(2) { |i| Factory.create(:post, :created_at => "#{Time.now.year}-0#{i}-01 00:00:00") }
|
8
|
+
1.upto(2) { |i| Factory.create(:post, :created_at => "#{Time.now.year + 1}-0#{i}-01 00:00:00") }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "defaults" do
|
12
|
+
it "uses the current year" do
|
13
|
+
Post.archive_node.each { |p| p.created_at.year.should == Time.now.year }
|
14
|
+
end
|
15
|
+
|
16
|
+
it "ignores the month" do
|
17
|
+
Post.archive_node.should have(2).record
|
18
|
+
end
|
19
|
+
|
20
|
+
end # defaults
|
21
|
+
|
22
|
+
describe "overridable" do
|
23
|
+
it "allows to override the year" do
|
24
|
+
year = Time.now.year + 1
|
25
|
+
Post.archive_node(:year => year).each { |p| p.created_at.year.should == year }
|
26
|
+
end
|
27
|
+
|
28
|
+
it "allows to select a month" do
|
29
|
+
Post.archive_node(:year => Time.now.year, :month => 1).each { |p| p.created_at.month.should == 1 }
|
30
|
+
end
|
31
|
+
|
32
|
+
it "allows to override the year and select a month" do
|
33
|
+
Post.archive_node(:year => Time.now.year, :month => 1).should have(1).record
|
34
|
+
end
|
35
|
+
end # overridables
|
36
|
+
|
37
|
+
end # archive_node
|
38
|
+
end # ArchiveTree
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ArchiveTree do
|
4
|
+
|
5
|
+
describe "self included" do
|
6
|
+
|
7
|
+
it "should extend klass with its ArchiveTree::Core" do
|
8
|
+
[:archived_years, :archived_months, :archive_tree, :archive_node].each do |method|
|
9
|
+
Post.should respond_to method
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end # self.included
|
13
|
+
|
14
|
+
end # ArchiveTree
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ArchiveTree do
|
4
|
+
|
5
|
+
describe "acts_as_archive" do
|
6
|
+
|
7
|
+
it "should be a class method of ActiveRecord::Base" do
|
8
|
+
ActiveRecord::Base.should respond_to :acts_as_archive
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should raise exception for undefined fields" do
|
12
|
+
lambda do
|
13
|
+
class Post < ActiveRecord::Base
|
14
|
+
acts_as_archive :dummy
|
15
|
+
end
|
16
|
+
end.should raise_error(ArgumentError)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should raise exception for invalid fields" do
|
20
|
+
lambda do
|
21
|
+
class Post < ActiveRecord::Base
|
22
|
+
acts_as_archive :body
|
23
|
+
end
|
24
|
+
end.should raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
|
27
|
+
end # acts_as_archive
|
28
|
+
|
29
|
+
describe "archive tree" do
|
30
|
+
|
31
|
+
before :each do
|
32
|
+
[2007, 2008, 2009, 2010].each do |year|
|
33
|
+
5.times { |i| Factory.create(:post, :created_at => "#{year}-#{01 + i}-01 00:00:00") }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "default behavior" do
|
38
|
+
|
39
|
+
it "should return an empty hash when there are no records" do
|
40
|
+
Post.destroy_all
|
41
|
+
|
42
|
+
Post.archive_tree.should == {}
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return the archive tree for all posts" do
|
46
|
+
tree = {}
|
47
|
+
[2007, 2008, 2009, 2010].each_with_index do |year, year_index|
|
48
|
+
tree[year] = {}
|
49
|
+
0.upto(4).each { |i| tree[year][i+1] = [Post.find(Post.first.id + year_index*5 + i)] }
|
50
|
+
end
|
51
|
+
|
52
|
+
Post.archive_tree.should == tree
|
53
|
+
end
|
54
|
+
|
55
|
+
end # default behavior
|
56
|
+
|
57
|
+
describe "years to sweep" do
|
58
|
+
|
59
|
+
it "accepts a years key in the options hash and complies to it" do
|
60
|
+
tree = {}
|
61
|
+
[2009, 2010].each_with_index do |year, year_index|
|
62
|
+
tree[year] = {}
|
63
|
+
0.upto(4).each { |i| tree[year][i+1] = [Post.find(10 + Post.first.id + year_index*5 + i)] }
|
64
|
+
end
|
65
|
+
|
66
|
+
Post.archive_tree(:years => [2009, 2010]).should == tree
|
67
|
+
end
|
68
|
+
|
69
|
+
end # years to sweep
|
70
|
+
|
71
|
+
describe "months to sweep" do
|
72
|
+
|
73
|
+
it "should only sweep January" do
|
74
|
+
tree = {}
|
75
|
+
[2007, 2008, 2009, 2010].each_with_index do |year, year_index|
|
76
|
+
tree[year] = {}
|
77
|
+
tree[year][1] = [Post.find(Post.first.id + year_index*5)]
|
78
|
+
end
|
79
|
+
|
80
|
+
Post.archive_tree(:months => [1]).should == tree
|
81
|
+
end
|
82
|
+
|
83
|
+
end # months to sweep
|
84
|
+
|
85
|
+
describe "years and months" do
|
86
|
+
|
87
|
+
it "should comply with the requested years and months filter" do
|
88
|
+
tree = { 2007 => { 1 => [Post.find(Post.first.id)] },
|
89
|
+
2008 => { 2 => [Post.find(Post.first.id + 6)], 3 => [Post.find(Post.first.id + 7)] } }
|
90
|
+
|
91
|
+
Post.archive_tree(:years_and_months => { 2007 => [1], 2008 => [2, 3] }).should == tree
|
92
|
+
end
|
93
|
+
|
94
|
+
end # years and months
|
95
|
+
|
96
|
+
end # archive_tree
|
97
|
+
|
98
|
+
end # ArchiveTree
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ArchiveTree do
|
4
|
+
|
5
|
+
describe "archived months" do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
2.times do |i|
|
9
|
+
Factory.create(:post, :created_at => "#{Time.now.year + i}-01-01 00:00:00")
|
10
|
+
Factory.create(:post, :created_at => "#{Time.now.year + i}-02-01 00:00:00")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns an empty hash if no records exist for a given year" do
|
15
|
+
Post.archived_months(:year => 3000).should == {}
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns an integer months counter hash" do
|
19
|
+
Post.archived_months.should == { 1 => 1, 2 => 1 }
|
20
|
+
end
|
21
|
+
|
22
|
+
it "defaults it's sweep year to the current year" do
|
23
|
+
Factory.create :post, :created_at => "#{Time.now.year}-#{12}-01 00:00:00"
|
24
|
+
Post.archived_months == { 1 => 1, 2 => 1, 12 => 1 }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "allows the invoker to specify the year being sweeped" do
|
28
|
+
Post.archived_months(:year => (Time.now.year + 1)).should == { 1 => 1, 2 => 1 }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "allows the type of month name to be specified as short" do
|
32
|
+
Post.archived_months(:month_names => :short).should == { "Jan" => 1, "Feb" => 1 }
|
33
|
+
end
|
34
|
+
|
35
|
+
it "allows the type of month name to be specified as long" do
|
36
|
+
Post.archived_months(:month_names => :long).should == { "January" => 1, "February" => 1 }
|
37
|
+
end
|
38
|
+
|
39
|
+
it "defaults to :month_names => :int whenever an unknown value is passed" do
|
40
|
+
Post.archived_months(:month_names => :invalid_value).should == { 1 => 1, 2 => 1 }
|
41
|
+
end
|
42
|
+
|
43
|
+
it "discards dates that are null" do
|
44
|
+
Post.first.update_attributes(:created_at => nil)
|
45
|
+
Post.archived_months.should == { 2 => 1 }
|
46
|
+
end
|
47
|
+
end # archived_months
|
48
|
+
|
49
|
+
end # ArchiveTree
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ArchiveTree do
|
4
|
+
|
5
|
+
describe "archived years" do
|
6
|
+
|
7
|
+
it "returns an empty hash if no years are archived" do
|
8
|
+
Post.archived_years.should == {}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns a years counter hash" do
|
12
|
+
2.times { |i| Factory.create(:post, :created_at => "#{Time.now.year + i}-#{01 + i}-01 00:00:00") }
|
13
|
+
|
14
|
+
Post.archived_years.should == { Time.now.year => 1, (Time.now.year + 1) => 1 }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "discards dates that are null" do
|
18
|
+
2.times { |i| Factory.create(:post, :created_at => "#{Time.now.year + i}-#{01 + i}-01 00:00:00") }
|
19
|
+
|
20
|
+
Post.last.update_attributes(:created_at => nil)
|
21
|
+
|
22
|
+
Post.archived_years.should == { Time.now.year => 1 }
|
23
|
+
end
|
24
|
+
|
25
|
+
end # archived_years
|
26
|
+
|
27
|
+
end # ArchiveTree
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) unless $:.include? File.dirname(__FILE__)
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__), '..') unless $:.include? File.join(File.dirname(__FILE__), '..')
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'init'
|
6
|
+
require 'erb'
|
7
|
+
require 'logger'
|
8
|
+
require 'rspec'
|
9
|
+
require 'active_record'
|
10
|
+
require 'database_cleaner'
|
11
|
+
require 'factory_girl'
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.debug = true
|
15
|
+
# == Mock Framework
|
16
|
+
config.mock_with :rspec
|
17
|
+
|
18
|
+
# database_cleaner
|
19
|
+
config.before(:suite) do
|
20
|
+
DatabaseCleaner.strategy = :transaction
|
21
|
+
DatabaseCleaner.clean_with(:truncation)
|
22
|
+
end
|
23
|
+
|
24
|
+
config.before(:each) do
|
25
|
+
DatabaseCleaner.start
|
26
|
+
end
|
27
|
+
|
28
|
+
config.after(:each) do
|
29
|
+
DatabaseCleaner.clean
|
30
|
+
end
|
31
|
+
end
|
32
|
+
rescue LoadError => load_error
|
33
|
+
puts "Please run bundle install"
|
34
|
+
rescue StandardError => e
|
35
|
+
puts "Something went wrong while loading the environment."
|
36
|
+
throw e
|
37
|
+
end
|
38
|
+
|
39
|
+
# Requires supporting files with custom matchers and macros, etc, in ./support/ and its subdirectories.
|
40
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
41
|
+
|
42
|
+
# Requires all supporting factories
|
43
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'factories', '*_factory.rb')).each { |f| require f }
|
44
|
+
|
45
|
+
# ActiveRecord Test database configurations
|
46
|
+
database_yml_file = File.expand_path('../config/database.yml', __FILE__)
|
47
|
+
|
48
|
+
begin
|
49
|
+
if File.exists?(database_yml_file)
|
50
|
+
active_record_configuration = YAML.load_file(database_yml_file)['test']
|
51
|
+
ActiveRecord::Base.establish_connection(active_record_configuration)
|
52
|
+
ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), 'log', 'test.log'))
|
53
|
+
|
54
|
+
ActiveRecord::Base.silence do
|
55
|
+
ActiveRecord::Migration.verbose = false
|
56
|
+
|
57
|
+
load File.join(File.dirname(__FILE__), 'db', 'schema.rb')
|
58
|
+
load File.join(File.dirname(__FILE__), 'db' , 'models.rb')
|
59
|
+
end
|
60
|
+
|
61
|
+
# The config/database.yml is in the spec folder
|
62
|
+
DatabaseCleaner.app_root = File.expand_path('spec')
|
63
|
+
else
|
64
|
+
raise "Please create #{database_yml} first. Take a look at the database.sample.yml in the config folder."
|
65
|
+
end
|
66
|
+
rescue StandardError => e
|
67
|
+
puts "Something went wrong while attempting to load your database file, or while configuring ActiveRecord."
|
68
|
+
throw e
|
69
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: archive_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.0.rc3
|
9
|
+
version: 1.0.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Diogo Almeida
|
@@ -16,7 +15,7 @@ autorequire:
|
|
16
15
|
bindir: bin
|
17
16
|
cert_chain: []
|
18
17
|
|
19
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-09 00:00:00 +00:00
|
20
19
|
default_executable:
|
21
20
|
dependencies:
|
22
21
|
- !ruby/object:Gem::Dependency
|
@@ -30,36 +29,100 @@ dependencies:
|
|
30
29
|
segments:
|
31
30
|
- 3
|
32
31
|
- 0
|
33
|
-
-
|
34
|
-
version: 3.0.
|
32
|
+
- 1
|
33
|
+
version: 3.0.1
|
35
34
|
type: :runtime
|
36
35
|
version_requirements: *id001
|
37
36
|
- !ruby/object:Gem::Dependency
|
38
|
-
name:
|
37
|
+
name: actionpack
|
39
38
|
prerelease: false
|
40
39
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
40
|
none: false
|
42
41
|
requirements:
|
43
|
-
- -
|
42
|
+
- - ~>
|
44
43
|
- !ruby/object:Gem::Version
|
45
44
|
segments:
|
45
|
+
- 3
|
46
46
|
- 0
|
47
|
-
|
48
|
-
|
47
|
+
- 1
|
48
|
+
version: 3.0.1
|
49
|
+
type: :runtime
|
49
50
|
version_requirements: *id002
|
50
51
|
- !ruby/object:Gem::Dependency
|
51
|
-
name:
|
52
|
+
name: mysql
|
52
53
|
prerelease: false
|
53
54
|
requirement: &id003 !ruby/object:Gem::Requirement
|
54
55
|
none: false
|
55
56
|
requirements:
|
56
|
-
- -
|
57
|
+
- - ~>
|
57
58
|
- !ruby/object:Gem::Version
|
58
59
|
segments:
|
60
|
+
- 2
|
61
|
+
- 8
|
59
62
|
- 0
|
60
|
-
version:
|
63
|
+
version: 2.8.0
|
61
64
|
type: :development
|
62
65
|
version_requirements: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: ruby-debug19
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ~>
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
- 11
|
77
|
+
- 0
|
78
|
+
version: 0.11.0
|
79
|
+
type: :development
|
80
|
+
version_requirements: *id004
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rspec
|
83
|
+
prerelease: false
|
84
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
segments:
|
90
|
+
- 2
|
91
|
+
- 0
|
92
|
+
- 0
|
93
|
+
version: 2.0.0
|
94
|
+
type: :development
|
95
|
+
version_requirements: *id005
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: factory_girl_rails
|
98
|
+
prerelease: false
|
99
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ~>
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
segments:
|
105
|
+
- 1
|
106
|
+
- 0
|
107
|
+
- 0
|
108
|
+
version: 1.0.0
|
109
|
+
type: :development
|
110
|
+
version_requirements: *id006
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: database_cleaner
|
113
|
+
prerelease: false
|
114
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ~>
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
- 6
|
122
|
+
- 0
|
123
|
+
version: 0.6.0
|
124
|
+
type: :development
|
125
|
+
version_requirements: *id007
|
63
126
|
description: ArchiveTree is a Ruby Gem that makes it easy for you to create beautiful chronological archive trees of your models. For instance, you can create a tree for your blog posts.
|
64
127
|
email:
|
65
128
|
- mail@gnomeslab.com
|
@@ -70,12 +133,24 @@ extensions: []
|
|
70
133
|
extra_rdoc_files: []
|
71
134
|
|
72
135
|
files:
|
73
|
-
- lib/archive_tree/action_view_extensions/draw_archive_tree.rb
|
74
136
|
- lib/archive_tree/action_view_extensions.rb
|
75
137
|
- lib/archive_tree/core.rb
|
76
138
|
- lib/archive_tree.rb
|
139
|
+
- Gemfile
|
140
|
+
- Gemfile.lock
|
77
141
|
- MIT-LICENSE
|
142
|
+
- Rakefile
|
78
143
|
- README.md
|
144
|
+
- spec/db/models.rb
|
145
|
+
- spec/db/schema.rb
|
146
|
+
- spec/factories/posts_factory.rb
|
147
|
+
- spec/lib/action_view_extensions/action_view_extensions_spec.rb
|
148
|
+
- spec/lib/archive_node_spec.rb
|
149
|
+
- spec/lib/archive_tree_core_spec.rb
|
150
|
+
- spec/lib/archive_tree_spec.rb
|
151
|
+
- spec/lib/archived_months_spec.rb
|
152
|
+
- spec/lib/archived_years_spec.rb
|
153
|
+
- spec/spec_helper.rb
|
79
154
|
has_rdoc: true
|
80
155
|
homepage: http://github.com/GnomesLab/archive_tree/
|
81
156
|
licenses: []
|
@@ -85,6 +160,7 @@ rdoc_options: []
|
|
85
160
|
|
86
161
|
require_paths:
|
87
162
|
- lib
|
163
|
+
- lib
|
88
164
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
165
|
none: false
|
90
166
|
requirements:
|
@@ -109,6 +185,6 @@ rubyforge_project:
|
|
109
185
|
rubygems_version: 1.3.7
|
110
186
|
signing_key:
|
111
187
|
specification_version: 3
|
112
|
-
summary: Creates chronological trees of your models based on
|
188
|
+
summary: Creates chronological trees of your models based on column of your choice.
|
113
189
|
test_files: []
|
114
190
|
|
@@ -1,76 +0,0 @@
|
|
1
|
-
module ArchiveTree
|
2
|
-
module ActionViewExtensions
|
3
|
-
|
4
|
-
# Defines the helper methods that will be included in the ActionView::Base in
|
5
|
-
# order to return the html representation of the archive tree
|
6
|
-
module DrawArchiveTree
|
7
|
-
|
8
|
-
# In the presence of records for a given model it draws the archive tree. Otherwise, returns an empty string
|
9
|
-
#
|
10
|
-
# This method relies on the following private methods:
|
11
|
-
# * +draw_years+
|
12
|
-
# * +draw_months+
|
13
|
-
#
|
14
|
-
# Default behavior
|
15
|
-
# * It will attempt to create a tree of your Post model
|
16
|
-
# * Will use the posts_path route
|
17
|
-
# * Will display a toggle link
|
18
|
-
# * Will use "[ + ]" as the text for the toggle link
|
19
|
-
#
|
20
|
-
# Options
|
21
|
-
# * model_sym #=> the symbol of the model to request the archive_nodes
|
22
|
-
# * route #=> the route that handles the archived posts requests
|
23
|
-
# * toggle #=> when true, includes a toggle link before the years
|
24
|
-
# * toggle_text #=> the text used in the toggle link
|
25
|
-
#
|
26
|
-
# Example using the default settings:
|
27
|
-
# <%= draw_archive_tree %>
|
28
|
-
#
|
29
|
-
# Overriding the defaults example:
|
30
|
-
# <%= draw_archive_tree :model_sym => :post, :route => :archive_published_at_path, :toggle => false %>
|
31
|
-
|
32
|
-
def draw_archive_tree(options = {})
|
33
|
-
options.reverse_merge!({ :model_sym => :post, :route => :posts_path, :toggle => true, :toggle_text => '[ + ]' })
|
34
|
-
model = options[:model_sym].to_s.capitalize.constantize
|
35
|
-
|
36
|
-
raw model.count > 0 ? draw_years(model, options[:route], options[:toggle], options[:toggle_text]) : ''
|
37
|
-
end # draw_archive_tree
|
38
|
-
|
39
|
-
private
|
40
|
-
def draw_years(model_sym, route, toggle, toggle_text) # :nodoc:
|
41
|
-
model = model_sym.to_s.capitalize.constantize
|
42
|
-
route = :posts_path unless self.respond_to? route
|
43
|
-
|
44
|
-
content_tag :ul do
|
45
|
-
ul_body = ""
|
46
|
-
|
47
|
-
model.archived_years.each_key do |year, count|
|
48
|
-
ul_body << content_tag(:li, :class => year == Time.now.year ? 'active' : 'inactive') do
|
49
|
-
(toggle ? link_to(toggle_text, "#", :class => "toggle") : '') + " " +
|
50
|
-
link_to(year, self.send(route, year)) +
|
51
|
-
draw_months(model_sym, route, year)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
ul_body
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def draw_months(model_sym, route, year) # :nodoc:
|
60
|
-
model = model_sym.to_s.capitalize.constantize
|
61
|
-
|
62
|
-
content_tag :ul do
|
63
|
-
ul_body = ""
|
64
|
-
|
65
|
-
model.archived_months(:year => year).each_pair do |month, count|
|
66
|
-
ul_body << content_tag(:li, link_to("#{Date::MONTHNAMES[month]} (#{count})",
|
67
|
-
self.send(route, year, month < 10 ? "0#{month}" : month)))
|
68
|
-
end
|
69
|
-
|
70
|
-
ul_body
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end # DrawArchiveTree
|
74
|
-
|
75
|
-
end # ActionViewExtensions
|
76
|
-
end # ArchiveTree
|