crumby 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ module Crumby::Helper
3
+ # view helper
4
+ module ViewHelper
5
+ # render breadcrumb
6
+ # @see Crumby::Trail#render
7
+ # @see Crumby::Renderer::Base
8
+ # @overload crumby(options)
9
+ # @param [Hash] options
10
+ # @param [Hash] options passthrough to renderer
11
+ # @overload crumby(scope, options)
12
+ # @param [Symbol, String] scope scope of breadcrumb
13
+ # @param [Hash] options passthrough to renderer
14
+ def crumby(*args)
15
+ options = args.extract_options!
16
+ scope = args.first || :default
17
+ crumby_trail(scope).render(self, options)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ # renderer package
2
+ module Crumby::Renderer
3
+ autoload :Base, 'crumby/renderer/base'
4
+ autoload :Haml, 'crumby/renderer/haml'
5
+
6
+ # Returns the default renderer
7
+ # @return [Crumby::Renderer::Base]
8
+ def self.default_renderer
9
+ Crumby.renderer
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ module Crumby::Renderer
3
+ # base for renderer
4
+ # @abstract
5
+ class Base
6
+ attr_reader :view, :trail, :options
7
+
8
+ def initialize(trail, view, options)
9
+ @trail = trail
10
+ @view = view
11
+ @options = default_options.merge options
12
+ end
13
+
14
+ # render trail
15
+ # @return [String] rendered trail
16
+ def render
17
+ render_list do
18
+ trail.entries.each do |entry|
19
+ render_entry(entry)
20
+ end
21
+ end
22
+ end
23
+
24
+ # empty default options
25
+ # @abstract
26
+ def default_options
27
+ {}
28
+ end
29
+
30
+ # @abstract
31
+ def render_list(&block)
32
+ raise NotImplementedError
33
+ end
34
+
35
+ # @abstract
36
+ def render_entry(entry)
37
+ raise NotImplementedError
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ module Crumby::Renderer
3
+ # haml renderer
4
+ class Haml < Base
5
+
6
+ # @return [Hash] default options for this renderer
7
+ def default_options
8
+ {
9
+ divider: "/",
10
+ link_last: false,
11
+ link_first: true
12
+ }
13
+ end
14
+
15
+ # render list by block
16
+ # the block call render_entry for each entry
17
+ def render_list(&block)
18
+ view.capture_haml do
19
+ view.haml_tag :ul, class: "breadcrumb" do
20
+ yield
21
+ end
22
+ end
23
+ end
24
+
25
+ # render entry
26
+ # @param [Crumby::Entry] entry that will be rendered
27
+ def render_entry(entry)
28
+ view.haml_tag :li, class: (entry.last? ? 'active' : nil) do
29
+ if entry.route.nil? or (entry.last? and not options[:link_last]) or (entry.first? and not options[:link_first])
30
+ view.haml_concat entry.label
31
+ else
32
+ view.haml_concat view.link_to(entry.label, entry.route)
33
+ end
34
+ view.haml_tag "span.divider", options[:divider] unless entry.last?
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,121 @@
1
+ # encoding: utf-8
2
+ module Crumby
3
+
4
+ # it represent on breadcrumb trail
5
+ class Trail
6
+ attr_reader :entries
7
+
8
+ def initialize
9
+ @entries = []
10
+ end
11
+
12
+ # Returns total entries
13
+ # @return [Fixnum] total entries
14
+ def count
15
+ entries.count
16
+ end
17
+
18
+ # add a new entry
19
+ # @example
20
+ # add :books
21
+ # add @book
22
+ # add [:admin, @book]
23
+ # add "Books", :admin_books
24
+ # add "Books", [:admin,:books]
25
+ # add "Book", [:admin, @book]
26
+ # add "Google", "http://google.de"
27
+ # @overload render(combined)
28
+ # @param [Object] combined
29
+ # @overload render(label, route)
30
+ # @param [String] label the label passthrough to link_to
31
+ # @param [Symbol, Array, String] route route passthrough to link_to
32
+ #
33
+ # @return [Crumby::Entry] builded entry
34
+ def add(*args)
35
+ # extract options
36
+ options = args.extract_options!
37
+
38
+ # call without any arguments
39
+ raise ArgumentError, "Need arguments." if args.empty?
40
+
41
+ # process arguments
42
+ if args.count == 1
43
+ value = args.first
44
+ if value.is_a? String
45
+ label = value
46
+ elsif value.is_a? Symbol
47
+ label = value.to_s.humanize
48
+ route = value
49
+ elsif value.respond_to? :model_name
50
+ label = value.model_name.human
51
+ route = value
52
+ elsif value.kind_of? Array
53
+ if value.last.respond_to? :model_name
54
+ label = value.last.model_name.human
55
+ else
56
+ label = value.last.to_s.humanize
57
+ end
58
+ route = value
59
+ else
60
+ label = value.to_s.humanize
61
+ end
62
+ else
63
+ label = args.first
64
+ route = args.second
65
+ end
66
+
67
+ entry = Entry.new(self, count, label, route, options)
68
+ @entries << entry
69
+ entry
70
+ end
71
+
72
+ # render the trail by a renderer
73
+ # @overload render(view, options)
74
+ # @param [ActionView::Base] view
75
+ # @param [Hash] options passthrough to renderer
76
+ # @option options [Class] :renderer overwrite default renderer
77
+ #
78
+ # @return [String] rendered trail
79
+ def render(*args)
80
+ options = args.extract_options!
81
+ renderer_class = options[:renderer] || Crumby::Renderer.default_renderer
82
+ raise ArgumentError if not renderer_class.class == Class or not renderer_class.ancestors.include? Crumby::Renderer::Base
83
+ view = args.first
84
+ renderer_class.new(self, view, options).render
85
+ end
86
+
87
+ # build a title of trail e.g. for page title
88
+ # @example
89
+ # title
90
+ # title "The Site"
91
+ # title "The Site", divider: " - "
92
+ # @overload title(suffix, options)
93
+ # @param [String] suffix last item.
94
+ # @param [Hash] options
95
+ # @option options [String] :divider The divider. default is " » "
96
+ # @option options [Boolean] :reverse reverse the title building. default is true
97
+ # @option options [Boolean] :skip_first remove first entry. it is usefull
98
+ #
99
+ # @return [String] build title. e.g New Book » Books » Admin
100
+ def title(*args)
101
+ options = args.extract_options!
102
+ suffix = args.first
103
+
104
+ default_options = {
105
+ divider: " » ",
106
+ reverse: true,
107
+ skip_first: true
108
+ }
109
+ options = default_options.merge args.extract_options!
110
+
111
+ title_entries = entries
112
+ title_entries = title_entries[1..-1] if options[:skip_first]
113
+
114
+ title = title_entries.reverse.collect{ |e| e[:label] }
115
+ title += [suffix] if suffix.present?
116
+ title.join(options[:divider])
117
+ end
118
+
119
+ end
120
+
121
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+
4
+ describe Crumby::Entry do
5
+
6
+ context "#new" do
7
+ let(:entry_label) { "TestLabel" }
8
+ let(:entry_route) { :test }
9
+ let(:entry_options) { { test: true } }
10
+ let(:trail) { stub :trail }
11
+
12
+ subject { Crumby::Entry.new(trail, 1, entry_label, entry_route, entry_options) }
13
+
14
+ its(:trail) { should equal trail }
15
+ its(:position) { should eq 1 }
16
+ its(:label) { should eq entry_label }
17
+ its(:route) { should eq entry_route }
18
+ its(:options) { should eq entry_options }
19
+ end
20
+
21
+ context "on trail with 10 breadcrumb" do
22
+ let(:trail) { trail = stub :trail, count: 10 }
23
+
24
+ context "any breadcrumb" do
25
+ subject { Crumby::Entry.new trail, 0, "Test" }
26
+ its(:total) { should eq 10 }
27
+ end
28
+
29
+ context "first breadcrumb" do
30
+ subject { Crumby::Entry.new trail, 0, "Test" }
31
+ its(:first?) { should be_true }
32
+ its(:last?) { should_not be_true }
33
+ end
34
+
35
+ context "last breadcrumb" do
36
+ subject { Crumby::Entry.new trail, 9, "Test" }
37
+ its(:first?) { should_not be_true }
38
+ its(:last?) { should be_true }
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,168 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+ require "active_support/all"
4
+
5
+ # class DummyController
6
+ # include Crumby::Helper
7
+ # end
8
+
9
+ # describe Crumby::Helper do
10
+ # let(:controller) { DummyController.new }
11
+ # let(:options) { { the_options: true, the_options2: true } }
12
+
13
+ # describe "#crumby_trail" do
14
+
15
+ # let! (:default_trail) { controller.crumby_trail(:default) }
16
+ # let! (:different_trail) { controller.crumby_trail(:different) }
17
+
18
+ # it "should match default scope with \":default\"" do
19
+ # controller.crumby_trail(:default).should equal default_trail
20
+ # end
21
+
22
+ # it "should match default scope with \"default\"" do
23
+ # controller.crumby_trail("default").should equal default_trail
24
+ # end
25
+
26
+ # it "should match diffrent scope with \":diffrent\"" do
27
+ # controller.crumby_trail(:different).should equal different_trail
28
+ # end
29
+
30
+ # it "should not match default or diffrent scope with \":other\"" do
31
+ # controller.crumby_trail(:other).should_not equal default_trail
32
+ # controller.crumby_trail(:other).should_not equal different_trail
33
+ # end
34
+
35
+ # end
36
+
37
+ # describe "#add_crumby" do
38
+
39
+ # let(:label) { "Name" }
40
+ # let(:route) { :route }
41
+
42
+ # subject { controller.crumby_trail }
43
+
44
+ # it "should receive all arguments" do
45
+ # controller.crumby_trail.should_receive(:add).with(label, route, options)
46
+ # controller.add_crumby(label, route, options)
47
+ # end
48
+
49
+ # context "with a diffrent scope" do
50
+ # let(:scope) { :a_different }
51
+ # subject { controller.crumby_trail(scope) }
52
+
53
+ # it "should receive all arguments" do
54
+ # subject.should_receive(:add).with(label, route, kind_of(Hash))
55
+ # controller.add_crumby(label, route, scope: scope)
56
+ # end
57
+ # end
58
+ # end
59
+
60
+ # describe "#crumby_title" do
61
+ # let (:trail) { stub :trail, title: stub }
62
+
63
+ # before { controller.stub(:crumby_trail).and_return(trail) }
64
+
65
+ # context "with default scope" do
66
+ # context "without suffix" do
67
+ # after { controller.crumby_title }
68
+
69
+ # it "should load default trail" do
70
+ # controller.should_receive(:crumby_trail).with(:default)
71
+ # end
72
+
73
+ # it "should load title without suffix" do
74
+ # trail.should_receive(:title).with(kind_of(Hash))
75
+ # end
76
+ # end
77
+
78
+ # context "with suffix" do
79
+ # let(:suffix) { "test" }
80
+ # after { controller.crumby_title suffix }
81
+
82
+ # it "should load title with suffix" do
83
+ # trail.should_receive(:title).with(suffix, kind_of(Hash))
84
+ # end
85
+ # end
86
+
87
+ # context "with options" do
88
+ # after { controller.crumby_title options }
89
+
90
+ # it "should load title with options" do
91
+ # trail.should_receive(:title).with(options)
92
+ # end
93
+ # end
94
+
95
+
96
+ # end
97
+
98
+ # context "with different scope" do
99
+ # after { controller.crumby_title scope: :test}
100
+ # it "should load different trail" do
101
+ # controller.should_receive(:crumby_trail).with(:test)
102
+ # end
103
+ # end
104
+
105
+ # # it "should call title on trail" do
106
+ # # controller.crumby_trail.should_receive(:title).with(options)
107
+ # # controller.crumby_title options
108
+ # # end
109
+
110
+ # # context "with a diffrent scope" do
111
+ # # let(:scope) { :a_different }
112
+ # # subject { controller.crumby_trail(scope) }
113
+
114
+ # # it "should call title on trail" do
115
+ # # subject.should_receive(:title).with(any_args, kind_of(Hash))
116
+ # # controller.crumby_title(scope, {})
117
+ # # end
118
+ # # end
119
+
120
+ # end
121
+
122
+ # describe "#crumby" do
123
+ # let (:renderer) { stub :renderer, render: stub }
124
+ # let (:trail) { stub :trail, renderer: renderer }
125
+ # before { controller.stub(:crumby_trail).and_return(trail) }
126
+
127
+ # context "with default scope" do
128
+ # after { controller.crumby }
129
+
130
+ # it "should load crumb" do
131
+ # controller.should_receive(:crumby_trail).with(:default)
132
+ # end
133
+ # end
134
+
135
+ # context "with :test scope" do
136
+ # after { controller.crumby :test }
137
+
138
+ # it "should load crumb" do
139
+ # controller.should_receive(:crumby_trail).with(:test)
140
+ # end
141
+ # end
142
+
143
+ # context "with default renderer" do
144
+ # after { controller.crumby }
145
+
146
+ # it "should call renderer" do
147
+ # trail.should_receive(:renderer).with(nil)
148
+ # end
149
+
150
+ # it "should call render on renderer with options" do
151
+ # renderer.should_receive(:render).with(kind_of Hash)
152
+ # end
153
+ # end
154
+
155
+ # context "with custom renderer" do
156
+ # after { controller.crumby renderer: renderer, option: true }
157
+
158
+ # it "should call renderer" do
159
+ # trail.should_receive(:renderer).with(renderer)
160
+ # end
161
+
162
+ # it "should call render on renderer with options" do
163
+ # renderer.should_receive(:render).with(hash_including(option: true))
164
+ # end
165
+ # end
166
+ # end
167
+
168
+ # end