radiant-sibling_tags-extension 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in radiant-sibling_tags-extension.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ Sibling Tags
2
+ ============
3
+
4
+ This extension for Radiant provides tags allowing you to refer to the neighbouring siblings of a page.
5
+
6
+ Installation
7
+ ------------
8
+
9
+ If your Radiant site is running on version 0.6.9 or greater, you can install extensions very easily. If you are using an
10
+ older version of Radiant, don't worry, it is still quite straightforward. Instructions follow for both.
11
+
12
+
13
+ ### Installing for Radiant 1.0
14
+
15
+ In a terminal, `cd` to the root directory of your Radiant site.
16
+
17
+ Add the following line to your Gemfile
18
+
19
+ gem 'radiant-sibling-tags-extension'
20
+
21
+ Run
22
+
23
+ bundle install
24
+
25
+ ### Installing for Radiant 0.6.9+
26
+
27
+ In a terminal, `cd` to the root directory of your Radiant site. Run the following command:
28
+
29
+ script/extension install sibling_tags
30
+
31
+ That's it!
32
+
33
+ ### Installing for Radiant pre-0.6.9
34
+
35
+ This extension is hosted on github. If you have git installed, then `cd` to the root of your radiant project and
36
+ issue this command:
37
+
38
+ git clone git://github.com/nelstrom/radiant-sibling-tags-extension.git vendor/extensions/sibling_tags
39
+
40
+ If you don’t have git, then you can instead download the tarball from this URL:
41
+
42
+ http://github.com/nelstrom/radiant-sibling-tags-extension/tarball/master
43
+
44
+ and expand the contents to `your-radiant-project/vendor/extensions/sibling_tags`.
45
+
46
+ This extension does not modify the database, so there is no need to run any migrations. Your done!
47
+
48
+ Usage
49
+ -----
50
+
51
+ When you restart you Radiant site, you should have access to the sibling tags in regular pages of your site.
52
+ Documentation for each individual tag is provided within Radiant. If you go to edit a page, then click the '<b>Available
53
+ tags</b>' link, you should see a list of all the available tags. You can filter the list, by typing 'sibling' into the
54
+ field at the top right of the window.
55
+
56
+ For examples of usage, we'll use the following site map:
57
+
58
+ Title Date of Publication
59
+ ---------------- -------------------
60
+ Home
61
+ \_Articles
62
+ \_Apple 2008-02-29
63
+ \_Brocolli 2007-12-17
64
+ \_Carrot 2008-01-25
65
+
66
+ Using the sibling tags, you can access immediate neighbours of a page. But which pages are considered neighbours depends
67
+ upon how you shuffle the deck! You can sort pages by any field that is stored in the database. Most likely you will want
68
+ to sort by date of publication, or by page title. These could also be arranged in ascending or descending order.
69
+
70
+ By default, pages are sorted in ascending order of publication, i.e. from oldest to newest. The children of 'Articles'
71
+ in the above site map would be arranged as follows:
72
+
73
+ Default order: Brocolli, Carrot, Apple
74
+
75
+ Lets examine the following snippet of code:
76
+
77
+ <r:siblings>
78
+ <r:previous>Previous article: <r:link/></r:previous>
79
+ <r:next>Next article: <r:link/></r:next>
80
+ </r:siblings>
81
+
82
+ If this was called on the 'Carrot' page, it would output:
83
+
84
+ Previous article: <a href="/articles/brocolli">Brocolli</a>
85
+ Next article: <a href="/articles/apple">Apple</a>
86
+
87
+ Whereas, if the same snippet was called from the 'Brocolli' page, it would output:
88
+
89
+ Next article: <a href="/articles/carrot">Carrot</a>
90
+
91
+ When arranged in the default sort order, 'Brocolli' comes first, so it has no predecessor. Hence, the contents of the
92
+ `<r:siblings:previous></r:siblings:previous>` tag are not output.
93
+
94
+ You can change the sort order using the `order` and `by` attributes. `order` can either be
95
+ `asc` or `desc`, whereas `by` can be any column name associated with a page in the database.
96
+
97
+ The following lists demonstrate how the 'Articles' pages above could be sorted:
98
+
99
+ order="desc": Apple, Carrot, Brocolli
100
+ by="title": Apple, Brocolli, Carrot
101
+ by="title" order="desc": Carrot, Brocolli, Apple
102
+
103
+ Remember that the default values are `order="asc"` and `by="published_at"`, so if either of these are not
104
+ specified, they fall back to those values.
105
+
106
+ This example demonstrates how these sorting options may be applied:
107
+
108
+ <r:siblings by="title">
109
+ <r:previous>Previous in alphabet:<r:link/></r:previous>
110
+ <r:unless_previous>This is the start of the alphabet.</r:unless_previous>
111
+ <r:next>Next in alphabet: <r:link/></r:next>
112
+ <r:unless_next>This is the end of the alphabet.</r:unless_next>
113
+ </r:siblings>
114
+
115
+ Where do the conditions go?
116
+ ---------------------------
117
+
118
+ You can specify `order` and `by` attributes inside of the `<r:siblings/>` tag itself, and these conditions are inherited by the child tags. The following examples are equivalent:
119
+
120
+ <r:siblings>
121
+ <r:previous by="title"><r:link/></r:previous>
122
+ <r:next by="title"><r:link/></r:next>
123
+ </r:siblings>
124
+
125
+ <r:siblings by="title">
126
+ <r:previous><r:link/></r:previous>
127
+ <r:next><r:link/></r:next>
128
+ </r:siblings>
129
+
130
+ By placing the `by` attribute in the `<r:siblings/>` tag, we can save on repetition. If you are planning on using both `<r:previous/>` and `<r:next/>` tags, then the second example is neater. However, if you just want to fetch one of the two, then you don't even have to nest the tags within a `<r:siblings/>` tag. Just make sure that you specify the full namespace at once, e.g.:
131
+
132
+ <r:siblings:previous by="title"><r:link/></r:siblings:previous>
133
+
134
+ <r:siblings:next by="title"><r:link/></r:siblings:next>
135
+
136
+ When you specify conditions in the `<r:siblings/>` tag, they are inherited by nested tags, but they may also be overridden. E.g.:
137
+
138
+ <r:siblings by="title" order="asc">
139
+ <r:next>Next alphabetically: <r:link/></r:next>
140
+ <r:previous>Previous alphabetically: <r:link/></r:previous>
141
+
142
+ <r:next by="published_at">Next chronologically</r:next>
143
+ <r:previous by="published_at">Previous chronologically</r:previous>
144
+ </r:siblings>
145
+
146
+ In this example, the first usage of `<r:next/>` and `<r:previous/>` inherit the attributes set in `<r:siblings/>`. The second time these same tags are used, they provide their own attributes, and these override the values set by the parent `<r:siblings/>` tag.
147
+
148
+
149
+ Credits
150
+ -------
151
+
152
+ Jim Gay created the `siblings:each`, `each_before` and `each_after` tags.
data/Rakefile ADDED
@@ -0,0 +1,128 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require "bundler/gem_tasks"
3
+
4
+ # I think this is the one that should be moved to the extension Rakefile template
5
+
6
+ # In rails 1.2, plugins aren't available in the path until they're loaded.
7
+ # Check to see if the rspec plugin is installed first and require
8
+ # it if it is. If not, use the gem version.
9
+
10
+ # Determine where the RSpec plugin is by loading the boot
11
+ unless defined? RADIANT_ROOT
12
+ ENV["RAILS_ENV"] = "test"
13
+ boot = if ENV["RADIANT_ENV_FILE"]
14
+ File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
15
+ elsif File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
16
+ "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
17
+ else
18
+ "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
19
+ end
20
+ begin
21
+ require boot
22
+ rescue LoadError => e
23
+ warn "Can’t boot radiant, #{e.message}"
24
+ end
25
+ end
26
+
27
+ require 'rake'
28
+ require 'rake/rdoctask'
29
+ require 'rake/testtask'
30
+
31
+ if defined? RADIANT_ROOT
32
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
33
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
34
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
35
+ Object.send(:remove_const, :RADIANT_ROOT)
36
+ end
37
+ require 'spec/rake/spectask'
38
+ # require 'spec/translator'
39
+
40
+ extension_root = File.expand_path(File.dirname(__FILE__))
41
+
42
+ task :default => :spec
43
+ task :stats => "spec:statsetup"
44
+
45
+ desc "Run all specs in spec directory"
46
+ Spec::Rake::SpecTask.new(:spec) do |t|
47
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
48
+ t.spec_files = FileList['spec/**/*_spec.rb']
49
+ end
50
+
51
+ namespace :spec do
52
+ desc "Run all specs in spec directory with RCov"
53
+ Spec::Rake::SpecTask.new(:rcov) do |t|
54
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
55
+ t.spec_files = FileList['spec/**/*_spec.rb']
56
+ t.rcov = true
57
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
58
+ end
59
+
60
+ desc "Print Specdoc for all specs"
61
+ Spec::Rake::SpecTask.new(:doc) do |t|
62
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
63
+ t.spec_files = FileList['spec/**/*_spec.rb']
64
+ end
65
+
66
+ [:models, :controllers, :views, :helpers].each do |sub|
67
+ desc "Run the specs under spec/#{sub}"
68
+ Spec::Rake::SpecTask.new(sub) do |t|
69
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
70
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
71
+ end
72
+ end
73
+
74
+ # Hopefully no one has written their extensions in pre-0.9 style
75
+ # desc "Translate specs from pre-0.9 to 0.9 style"
76
+ # task :translate do
77
+ # translator = ::Spec::Translator.new
78
+ # dir = RAILS_ROOT + '/spec'
79
+ # translator.translate(dir, dir)
80
+ # end
81
+
82
+ # Setup specs for stats
83
+ task :statsetup do
84
+ require 'code_statistics'
85
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
86
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
87
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
88
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
89
+ ::CodeStatistics::TEST_TYPES << "Model specs"
90
+ ::CodeStatistics::TEST_TYPES << "View specs"
91
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
92
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
93
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
94
+ end
95
+
96
+ namespace :db do
97
+ namespace :fixtures do
98
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
99
+ task :load => :environment do
100
+ require 'active_record/fixtures'
101
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
102
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
103
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ desc 'Generate documentation for the sibling_tags extension.'
111
+ Rake::RDocTask.new(:rdoc) do |rdoc|
112
+ rdoc.rdoc_dir = 'rdoc'
113
+ rdoc.title = 'SiblingTagsExtension'
114
+ rdoc.options << '--line-numbers' << '--inline-source'
115
+ rdoc.rdoc_files.include('README')
116
+ rdoc.rdoc_files.include('lib/**/*.rb')
117
+ end
118
+
119
+ # For extensions that are in transition
120
+ desc 'Test the sibling_tags extension.'
121
+ Rake::TestTask.new(:test) do |t|
122
+ t.libs << 'lib'
123
+ t.pattern = 'test/**/*_test.rb'
124
+ t.verbose = true
125
+ end
126
+
127
+ # Load any custom rakefiles for extension
128
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
@@ -0,0 +1,223 @@
1
+ module SiblingTags
2
+ include Radiant::Taggable
3
+
4
+ desc %{
5
+ Set's the scope for a page's siblings.
6
+
7
+ The order in which siblings are sorted can be manipulated using all the same attributes
8
+ as the @<r:children:each/>@ tag. If no attributes are supplied, the siblings will
9
+ have order = "published_at ASC". The @by@ attribute allows you to order by any page
10
+ properties stored in the database, the most likely of these to be useful are
11
+ @published_at@ and @title@.
12
+
13
+ Values set in the @<r:siblings/>@ tag will be inherited by tags nested within,
14
+ but may also be overridden in the child tags.
15
+
16
+ *Usage:*
17
+ <pre><code><r:siblings [by="published_at|title"] [order="asc|desc"] [status="published|all"]/>
18
+ <r:next><r:link/></r:next>
19
+ <r:previous><r:link/></r:previous>
20
+ </r:siblings></code></pre>
21
+ }
22
+ tag 'siblings' do |tag|
23
+ tag.locals.filter_attributes = tag.attr || {}
24
+ tag.expand
25
+ end
26
+
27
+ desc %{
28
+ Loops through each sibling and outputs the contents
29
+ }
30
+ tag 'siblings:each' do |tag|
31
+ result = []
32
+ inherit_filter_attributes(tag)
33
+ tag.locals.siblings = tag.locals.page.parent.children.find(:all, siblings_find_options(tag))
34
+ tag.locals.siblings.each do |sib|
35
+ tag.locals.page = sib
36
+ result << tag.expand
37
+ end
38
+ result
39
+ end
40
+
41
+ desc %{
42
+ Only renders the contents of this tag if the current page has any published siblings.
43
+ }
44
+ tag 'if_siblings' do |tag|
45
+ if parent = tag.locals.page.parent
46
+ if parent.children.find(:all, siblings_find_options(tag)).size > 0
47
+ tag.expand
48
+ end
49
+ end
50
+ end
51
+
52
+ desc %{
53
+ Only renders the contents of this tag if the current page has no published siblings.
54
+ }
55
+ tag 'unless_siblings' do |tag|
56
+ if !tag.locals.page.parent or tag.locals.page.parent.children.find(:all, siblings_find_options(tag)).size == 0
57
+ tag.expand
58
+ end
59
+ end
60
+
61
+ desc %{
62
+ Only render the contents of this tag if the current page has a sibling *after* it, when sorted according to the @order@ and @by@ options.
63
+
64
+ See @<siblings/>@ for a more detailed description of the sorting options.
65
+ }
66
+ tag 'siblings:if_next' do |tag|
67
+ inherit_filter_attributes(tag)
68
+ tag.expand if find_next_sibling(tag)
69
+ end
70
+
71
+ desc %{
72
+ Only render the contents of this tag if the current page has a sibling *before* it, when sorted according to the @order@ and @by@ options.
73
+
74
+ See @<siblings/>@ for a more detailed description of the sorting options.
75
+ }
76
+ tag 'siblings:if_previous' do |tag|
77
+ inherit_filter_attributes(tag)
78
+ tag.expand if find_previous_sibling(tag)
79
+ end
80
+
81
+ desc %{
82
+ Only render the contents of this tag if the current page is the last of its siblings, when sorted according to the @order@ and @by@ options.
83
+
84
+ See @<siblings/>@ for a more detailed description of the sorting options.
85
+ }
86
+ tag 'siblings:unless_next' do |tag|
87
+ inherit_filter_attributes(tag)
88
+ tag.expand unless find_next_sibling(tag)
89
+ end
90
+
91
+ desc %{
92
+ Only render the contents of this tag if the current page is the first of its siblings, when sorted according to the @order@ and @by@ options.
93
+
94
+ See @<siblings/>@ for a more detailed description of the sorting options.
95
+ }
96
+ tag 'siblings:unless_previous' do |tag|
97
+ inherit_filter_attributes(tag)
98
+ tag.expand unless find_previous_sibling(tag)
99
+ end
100
+
101
+ desc %{
102
+ All Radiant tags within a @<r:siblings:next/>@ block are interpreted in the context
103
+ of the next sibling page.
104
+
105
+ See @<siblings/>@ for a more detailed description of the sorting options.
106
+
107
+ *Usage:*
108
+ <pre><code><r:siblings:next [by="published_at|title"] [order="asc|desc"] [status="published|all"]/>...</r:siblings:next></code></pre>
109
+ }
110
+ tag 'siblings:next' do |tag|
111
+ inherit_filter_attributes(tag)
112
+ tag.expand if tag.locals.page = find_next_sibling(tag)
113
+ end
114
+
115
+ desc %{
116
+ Displays its contents for each of the following pages according to the given
117
+ attributes. See @<siblings>@ for details about the attributes.
118
+ }
119
+ tag 'siblings:each_before' do |tag|
120
+ inherit_filter_attributes(tag)
121
+ result = []
122
+ tag.locals.siblings = find_siblings_before(tag)
123
+ tag.locals.siblings.each do |sib|
124
+ tag.locals.page = sib
125
+ result << tag.expand
126
+ end
127
+ result
128
+ end
129
+
130
+ desc %{
131
+ All Radiant tags within a @<r:siblings:previous/>@ block are interpreted in the context
132
+ of the previous sibling page, when sorted according to the @order@ and @by@ options.
133
+
134
+ See @<siblings/>@ for a more detailed description of the sorting options.
135
+
136
+ *Usage:*
137
+ <pre><code><r:siblings:previous [by="published_at|title"] [order="asc|desc"]
138
+ [status="published|all"]/>...</r:siblings:previous></code></pre>
139
+ }
140
+ tag 'siblings:previous' do |tag|
141
+ inherit_filter_attributes(tag)
142
+ tag.expand if tag.locals.page = find_previous_sibling(tag)
143
+ end
144
+
145
+ desc %{
146
+ Displays its contents for each of the following pages according to the given
147
+ attributes. See @<siblings>@ for details about the attributes.
148
+ }
149
+ tag 'siblings:each_after' do |tag|
150
+ inherit_filter_attributes(tag)
151
+ result = []
152
+ tag.locals.siblings = find_siblings_after(tag)
153
+ tag.locals.siblings.each do |sib|
154
+ tag.locals.page = sib
155
+ result << tag.expand
156
+ end
157
+ result
158
+ end
159
+
160
+ private
161
+
162
+ def inherit_filter_attributes(tag)
163
+ tag.attr ||= {}
164
+ tag.attr.reverse_merge!(tag.locals.filter_attributes)
165
+ end
166
+
167
+ def find_next_sibling(tag)
168
+ if tag.locals.page.parent
169
+ tag.attr['adjacent'] = 'next'
170
+ tag.locals.page.parent.children.find(:first, adjacent_siblings_find_options(tag))
171
+ end
172
+ end
173
+
174
+ def find_siblings_before(tag)
175
+ if tag.locals.page.parent
176
+ tag.attr['adjacent'] = 'previous'
177
+ tag.locals.page.parent.children.find(:all, adjacent_siblings_find_options(tag)).reverse!
178
+ end
179
+ end
180
+
181
+ def find_previous_sibling(tag)
182
+ if tag.locals.page.parent
183
+ tag.attr['adjacent'] = 'previous'
184
+ sorted = tag.locals.page.parent.children.find(:all, adjacent_siblings_find_options(tag))
185
+ sorted.last unless sorted.blank?
186
+ end
187
+ end
188
+
189
+ def find_siblings_after(tag)
190
+ if tag.locals.page.parent
191
+ tag.attr['adjacent'] = 'next'
192
+ tag.locals.page.parent.children.find(:all, adjacent_siblings_find_options(tag))
193
+ end
194
+ end
195
+
196
+ def adjacent_siblings_find_options(tag)
197
+ options = siblings_find_options(tag)
198
+ adjacent_condition = attr_or_error(tag, :attribute_name => 'adjacent', :default => 'next', :values => 'next, previous')
199
+ attribute_sort = (tag.attr[:by] || tag.attr["by"] || 'published_at').strip
200
+ attribute_order = attr_or_error(tag, :attribute_name => 'order', :default => 'asc', :values => 'desc, asc')
201
+
202
+ find_less_than = " and (#{attribute_sort} < ?)"
203
+ find_greater_than = " and (#{attribute_sort} > ?)"
204
+
205
+ if attribute_order == "asc"
206
+ adjacent_find_condition = (adjacent_condition == 'previous' ? find_less_than : find_greater_than)
207
+ else
208
+ adjacent_find_condition = (adjacent_condition == 'previous' ? find_greater_than : find_less_than)
209
+ end
210
+
211
+ options[:conditions].first << adjacent_find_condition
212
+ options[:conditions] << tag.locals.page.send(attribute_sort)
213
+
214
+ options
215
+ end
216
+
217
+ def siblings_find_options(tag)
218
+ options = children_find_options(tag)
219
+ options[:conditions].first << ' and (id != ?)'
220
+ options[:conditions] << tag.locals.page.id
221
+ options
222
+ end
223
+ end
@@ -0,0 +1,5 @@
1
+ require 'radiant-sibling_tags-extension/version'
2
+
3
+ module RadiantSiblingTagsExtension
4
+ # dummy file for default gem requires
5
+ end
@@ -0,0 +1,3 @@
1
+ module RadiantSiblingTagsExtension
2
+ VERSION = '0.2.1'
3
+ end
@@ -0,0 +1,28 @@
1
+ namespace :radiant do
2
+ namespace :extensions do
3
+ namespace :sibling_tags do
4
+
5
+ desc "Runs the migration of the Sibling Tags extension"
6
+ task :migrate => :environment do
7
+ require 'radiant/extension_migrator'
8
+ if ENV["VERSION"]
9
+ SiblingTagsExtension.migrator.migrate(ENV["VERSION"].to_i)
10
+ else
11
+ SiblingTagsExtension.migrator.migrate
12
+ end
13
+ end
14
+
15
+ desc "Copies public assets of the Sibling Tags to the instance public/ directory."
16
+ task :update => :environment do
17
+ is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
18
+ Dir[SiblingTagsExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
19
+ path = file.sub(SiblingTagsExtension.root, '')
20
+ directory = File.dirname(path)
21
+ puts "Copying #{path}..."
22
+ mkdir_p RAILS_ROOT + directory
23
+ cp file, RAILS_ROOT + path
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require 'radiant-sibling_tags-extension/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'radiant-sibling_tags-extension'
7
+ s.version = RadiantSiblingTagsExtension::VERSION
8
+ s.authors = ['Drew Neil']
9
+ s.email = ['andrew.jr.neil@gmail.com']
10
+ s.homepage = 'http://github.com/nelstrom/radiant-sibling-tags-extension'
11
+ s.summary = 'This extension for Radiant provides tags allowing you to refer to the neighbouring siblings of a page'
12
+ s.description = 'This extension for Radiant provides tags allowing you to refer to the neighbouring siblings of a page'
13
+
14
+ s.rubyforge_project = 'radiant-sibling_tags-extension'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_development_dependency 'bundler'
22
+ s.add_development_dependency 'rspec'
23
+ end
@@ -0,0 +1,15 @@
1
+ require 'radiant-sibling_tags-extension/version'
2
+
3
+ class SiblingTagsExtension < Radiant::Extension
4
+ version RadiantSiblingTagsExtension::VERSION
5
+ description "Allows you to refer to the current page's previous/next sibling."
6
+ url "http://github.com/nelstrom/radiant-sibling-tags-extension"
7
+
8
+ def activate
9
+ Page.send :include, SiblingTags
10
+ end
11
+
12
+ def deactivate
13
+ end
14
+
15
+ end
@@ -0,0 +1,170 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Sibling Tags" do
4
+ scenario :sibling_pages
5
+
6
+ describe "<r:siblings>" do
7
+ it "should expand its contents" do
8
+ page(:sneezy).should render('<r:siblings>true</r:siblings>').as('true')
9
+ end
10
+ end
11
+ describe "<r:siblings:each>" do
12
+ it "should order the page siblings by published_at" do
13
+ page(:sneezy).should render('<r:siblings:each><r:title/> </r:siblings:each>').as('Happy Grumpy Dopey Doc Bashful ')
14
+ end
15
+ it "should allow siblings to be ordered by the 'by' attribute" do
16
+ page(:sneezy).should render('<r:siblings:each by="title"><r:title /> </r:siblings:each>').as('Bashful Doc Dopey Grumpy Happy ')
17
+ page(:sneezy).should render('<r:siblings by="title"><r:each><r:title /> </r:each></r:siblings>').as('Bashful Doc Dopey Grumpy Happy ')
18
+ end
19
+ it "should allow siblings to be sorted with the 'order' attribute when using 'by'" do
20
+ page(:sneezy).should render('<r:siblings:each by="slug" order="asc"><r:title /> </r:siblings:each>').as('Bashful Doc Dopey Grumpy Happy ')
21
+ page(:sneezy).should render('<r:siblings by="slug" order="asc"><r:each><r:title /> </r:each></r:siblings>').as('Bashful Doc Dopey Grumpy Happy ')
22
+ end
23
+ it "should exclude the current page" do
24
+ page(:sneezy).should render('<r:siblings:each><r:title/> </r:siblings:each>').as('Happy Grumpy Dopey Doc Bashful ')
25
+ end
26
+ it "should exclude unpublished pages" do
27
+ page(:sneezy).should render('<r:siblings:each><r:title/> </r:siblings:each>').as('Happy Grumpy Dopey Doc Bashful ')
28
+ end
29
+ end
30
+
31
+ describe "<r:if_siblings>" do
32
+ it 'should output its contents if the current page has siblings' do
33
+ page(:happy).should render('<r:if_siblings>true</r:if_siblings>').as('true')
34
+ end
35
+ it 'should not output its contents if the current page has no siblings' do
36
+ page(:solo).should render('<r:if_siblings>false</r:if_siblings>').as('')
37
+ end
38
+ end
39
+
40
+ describe "<r:unless_siblings>" do
41
+ it 'should output its contents if the current page has no siblings' do
42
+ page(:solo).should render('<r:unless_siblings>true</r:unless_siblings>').as('true')
43
+ end
44
+ it 'should not output its contents if the current page has siblings' do
45
+ page(:happy).should render('<r:unless_siblings>false</r:unless_siblings>').as('')
46
+ end
47
+ end
48
+
49
+ describe "<r:siblings:next>" do
50
+ it 'should output nothing if the current page has no siblings' do
51
+ page(:home).should render('<r:siblings:next>false</r:siblings:next>').as('')
52
+ end
53
+ it 'should output its contents if the current page has a sibling next in order' do
54
+ page(:doc).should render('<r:siblings:next>true</r:siblings:next>').as('true')
55
+ end
56
+ it 'should not output its contents if the current page has siblings, but not next in order' do
57
+ page(:bashful).should render('<r:siblings:next>true</r:siblings:next>').as('')
58
+ end
59
+ it "should set the scoped page to the next page in order" do
60
+ page(:doc).should render('<r:siblings:next><r:title /></r:siblings:next>').as('Bashful')
61
+ end
62
+ it "should work recursively when called more than once" do
63
+ page(:dopey).should render('<r:siblings><r:next><r:next><r:title /></r:next></r:next></r:siblings>').as('Bashful')
64
+ end
65
+ it "should order with 'by' attribute in siblings tag" do
66
+ page(:dopey).should render('<r:siblings by="title"><r:next><r:title/></r:next></r:siblings>').as('Grumpy')
67
+ end
68
+ it "should order with 'by' attribute in next tag" do
69
+ page(:dopey).should render('<r:siblings:next by="title"><r:title/></r:siblings:next>').as('Grumpy')
70
+ end
71
+ end
72
+
73
+ describe "<r:siblings:each_before>" do
74
+ it "should render its contents for each sibling following the current one in order" do
75
+ page(:dopey).should render('<r:siblings:each_before><r:title /> </r:siblings:each_before>').as('Grumpy Happy Sneezy ')
76
+ end
77
+ it "should use 'order' and 'by' as set in siblings tag" do
78
+ page(:dopey).should render('<r:siblings order="desc"><r:each_before><r:title /> </r:each_before></r:siblings>').as('Doc Bashful ')
79
+ page(:dopey).should render('<r:siblings order="desc" by="title"><r:each_before><r:title /> </r:each_before></r:siblings>').as('Grumpy Happy Sneezy ')
80
+ end
81
+ it "should use 'order' and 'by' as set in each_before tag" do
82
+ page(:dopey).should render('<r:siblings:each_before order="desc"><r:title /> </r:siblings:each_before>').as('Doc Bashful ')
83
+ page(:dopey).should render('<r:siblings:each_before order="desc" by="title"><r:title /> </r:siblings:each_before>').as('Grumpy Happy Sneezy ')
84
+ end
85
+ end
86
+
87
+ describe "<r:siblings:each_after>" do
88
+ it "should render its contents for each sibling following the current one in order" do
89
+ page(:dopey).should render('<r:siblings:each_after><r:title /> </r:siblings:each_after>').as('Doc Bashful ')
90
+ end
91
+ it "should use 'order' and 'by' as set in siblings tag" do
92
+ page(:dopey).should render('<r:siblings order="desc"><r:each_after><r:title /> </r:each_after></r:siblings>').as('Grumpy Happy Sneezy ')
93
+ page(:dopey).should render('<r:siblings order="desc" by="title"><r:each_after><r:title /> </r:each_after></r:siblings>').as('Doc Bashful ')
94
+ end
95
+ it "should use 'order' and 'by' as set in each_after tag" do
96
+ page(:dopey).should render('<r:siblings:each_after order="desc" by="title"><r:title /> </r:siblings:each_after>').as('Doc Bashful ')
97
+ end
98
+ end
99
+
100
+ describe "<r:siblings:previous>" do
101
+ it 'should output nothing if the current page has no siblings' do
102
+ page(:home).should render('<r:siblings:previous>false</r:siblings:previous>').as('')
103
+ end
104
+ it 'should output its contents if the current page has a sibling previous in order' do
105
+ page(:doc).should render('<r:siblings:previous>true</r:siblings:previous>').as('true')
106
+ end
107
+ it 'should not output its contents if the current page has siblings, but not previous in order' do
108
+ page(:sneezy).should render('<r:siblings:previous>true</r:siblings:previous>').as('')
109
+ end
110
+ it "should set the scoped page to the previous page in order" do
111
+ page(:doc).should render('<r:siblings:previous><r:title /></r:siblings:previous>').as('Dopey')
112
+ end
113
+ it "should set the scoped page to the previous page in order" do
114
+ page(:doc).should render('<r:siblings:previous><r:previous><r:title /></r:previous></r:siblings:previous>').as('Grumpy')
115
+ end
116
+ it "should order with 'by' attribute in siblings tag" do
117
+ page(:dopey).should render('<r:siblings by="title"><r:previous><r:title/></r:previous></r:siblings>').as('Doc')
118
+ end
119
+ it "should order with 'by' attribute in previous tag" do
120
+ page(:dopey).should render('<r:siblings:previous by="title"><r:title/></r:siblings:previous>').as('Doc')
121
+ end
122
+ end
123
+
124
+ describe "<r:sibling:if_next>" do
125
+ it "should output its contents if the current page has a sibling next in order" do
126
+ page(:doc).should render('<r:siblings:if_next>true</r:siblings:if_next>').as('true')
127
+ end
128
+ it "should not output its contents if the current page has no sibling next in order" do
129
+ page(:bashful).should render('<r:siblings:if_next>true</r:siblings:if_next>').as('')
130
+ end
131
+ end
132
+
133
+ describe "<r:siblings:unless_next>" do
134
+ it "should output its contents if the current page has no sibling next in order" do
135
+ page(:bashful).should render('<r:siblings:unless_next>true</r:siblings:unless_next>').as('true')
136
+ end
137
+ it "should not output its contents if the current page has a sibling next in order" do
138
+ page(:doc).should render('<r:siblings:unless_next>true</r:siblings:unless_next>').as('')
139
+ end
140
+ end
141
+
142
+ describe "<r:siblings:if_previous>" do
143
+ it "should output its contents if the current page has a sibling previous in order" do
144
+ page(:doc).should render('<r:siblings:if_previous>true</r:siblings:if_previous>').as('true')
145
+ end
146
+ it "should not output its contents if the current page has no sibling previous in order" do
147
+ page(:sneezy).should render('<r:siblings:if_previous>true</r:siblings:if_previous>').as('')
148
+ end
149
+ end
150
+
151
+ describe "<r:siblings:unless_previous>" do
152
+ it "should output its contents if the current page has no sibling previous in order" do
153
+ page(:sneezy).should render('<r:siblings:unless_previous>true</r:siblings:unless_previous>').as('true')
154
+ end
155
+ it "should not output its contents if the current page has a sibling previous in order" do
156
+ page(:doc).should render('<r:siblings:unless_previous>true</r:siblings:unless_previous>').as('')
157
+ end
158
+ end
159
+
160
+ private
161
+
162
+ def page(symbol = nil)
163
+ if symbol.nil?
164
+ @page ||= pages(:assorted)
165
+ else
166
+ @page = pages(symbol)
167
+ end
168
+ end
169
+
170
+ end
@@ -0,0 +1,27 @@
1
+ class SiblingPagesScenario < Scenario::Base
2
+ uses :home_page
3
+
4
+ def load
5
+ create_page "Single mum" do
6
+ create_page "Solo", :published_at => DateTime.parse('2003-08-01 08:12:01')
7
+ end
8
+
9
+ create_page "Mother of two" do
10
+ create_page "Amy", :published_at => DateTime.parse('2003-01-01 08:12:01')
11
+ create_page "Kate", :published_at => DateTime.parse('2002-10-01 04:02:10')
12
+ end
13
+
14
+ create_page "Mother of dwarves" do
15
+ create_page "Bashful", :published_at => DateTime.parse('2005-10-07 12:12:12')
16
+ create_page "Doc", :published_at => DateTime.parse('2004-09-08 12:12:12')
17
+ create_page "Dopey", :published_at => DateTime.parse('2003-08-09 12:12:12')
18
+ create_page "Grumpy", :published_at => DateTime.parse('2002-07-10 12:12:12')
19
+ create_page "Happy", :published_at => DateTime.parse('2001-06-11 12:12:12')
20
+ create_page "Sleepy", :status_id => Status[:draft].id
21
+ create_page "Sneezy", :published_at => DateTime.parse('2000-05-12 12:12:12')
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ progress
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,37 @@
1
+ unless defined? RADIANT_ROOT
2
+ ENV["RAILS_ENV"] = "test"
3
+ case
4
+ when ENV["RADIANT_ENV_FILE"]
5
+ require ENV["RADIANT_ENV_FILE"]
6
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
7
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../../")}/config/environment"
8
+ else
9
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../")}/config/environment"
10
+ end
11
+ end
12
+ require "#{RADIANT_ROOT}/spec/spec_helper"
13
+
14
+ if File.directory?(File.dirname(__FILE__) + "/scenarios")
15
+ Scenario.load_paths.unshift File.dirname(__FILE__) + "/scenarios"
16
+ end
17
+ if File.directory?(File.dirname(__FILE__) + "/matchers")
18
+ Dir[File.dirname(__FILE__) + "/matchers/*.rb"].each {|file| require file }
19
+ end
20
+
21
+ Spec::Runner.configure do |config|
22
+ # config.use_transactional_fixtures = true
23
+ # config.use_instantiated_fixtures = false
24
+ # config.fixture_path = RAILS_ROOT + '/spec/fixtures'
25
+
26
+ # You can declare fixtures for each behaviour like this:
27
+ # describe "...." do
28
+ # fixtures :table_a, :table_b
29
+ #
30
+ # Alternatively, if you prefer to declare them only once, you can
31
+ # do so here, like so ...
32
+ #
33
+ # config.global_fixtures = :table_a, :table_b
34
+ #
35
+ # If you declare global fixtures, be aware that they will be declared
36
+ # for all of your examples, even those that don't use them.
37
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: radiant-sibling_tags-extension
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Drew Neil
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &70267021546480 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70267021546480
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70267021545860 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70267021545860
36
+ description: This extension for Radiant provides tags allowing you to refer to the
37
+ neighbouring siblings of a page
38
+ email:
39
+ - andrew.jr.neil@gmail.com
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - README.md
47
+ - Rakefile
48
+ - app/models/sibling_tags.rb
49
+ - lib/radiant-sibling-tags-extension.rb
50
+ - lib/radiant-sibling_tags-extension/version.rb
51
+ - lib/tasks/sibling_tags_extension_tasks.rake
52
+ - radiant-sibling_tags-extension.gemspec
53
+ - sibling_tags_extension.rb
54
+ - spec/models/sibling_tags_spec.rb
55
+ - spec/scenarios/sibling_pages_scenario.rb
56
+ - spec/spec.opts
57
+ - spec/spec_helper.rb
58
+ homepage: http://github.com/nelstrom/radiant-sibling-tags-extension
59
+ licenses: []
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project: radiant-sibling_tags-extension
78
+ rubygems_version: 1.8.11
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: This extension for Radiant provides tags allowing you to refer to the neighbouring
82
+ siblings of a page
83
+ test_files:
84
+ - spec/models/sibling_tags_spec.rb
85
+ - spec/scenarios/sibling_pages_scenario.rb
86
+ - spec/spec.opts
87
+ - spec/spec_helper.rb