crumby 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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