loaf 0.3.0 → 0.4.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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -8
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +23 -2
  5. data/Appraisals +18 -0
  6. data/CHANGELOG.md +12 -0
  7. data/Gemfile +16 -1
  8. data/README.md +69 -52
  9. data/Rakefile +5 -3
  10. data/bin/setup +7 -0
  11. data/gemfiles/rails3.2.gemfile +21 -0
  12. data/gemfiles/rails4.0.gemfile +22 -0
  13. data/gemfiles/rails4.1.gemfile +21 -0
  14. data/gemfiles/rails4.2.gemfile +21 -0
  15. data/lib/loaf.rb +24 -1
  16. data/lib/loaf/configuration.rb +15 -22
  17. data/lib/loaf/controller_extensions.rb +25 -12
  18. data/lib/loaf/crumb.rb +13 -1
  19. data/lib/loaf/crumb_formatter.rb +14 -13
  20. data/lib/loaf/options_validator.rb +10 -2
  21. data/lib/loaf/translation.rb +15 -8
  22. data/lib/loaf/version.rb +1 -8
  23. data/lib/loaf/view_extensions.rb +42 -15
  24. data/loaf.gemspec +10 -17
  25. data/spec/integration/configuration_spec.rb +7 -8
  26. data/spec/integration/crumbs_routing_spec.rb +31 -28
  27. data/spec/rails_app/app/controllers/application_controller.rb +0 -2
  28. data/spec/rails_app/app/controllers/posts_controller.rb +13 -2
  29. data/spec/rails_app/app/views/layouts/_breadcrumbs.html.erb +2 -0
  30. data/spec/rails_app/app/views/posts/index.html.erb +0 -2
  31. data/spec/rails_app/app/views/posts/new.html.erb +3 -0
  32. data/spec/rails_app/app/views/posts/show.html.erb +1 -0
  33. data/spec/rails_app/config/environments/development.rb +2 -0
  34. data/spec/rails_app/config/environments/production.rb +2 -0
  35. data/spec/rails_app/config/environments/test.rb +2 -3
  36. data/spec/rails_app/config/routes.rb +0 -2
  37. data/spec/rails_app/{app/mailers → log}/.gitkeep +0 -0
  38. data/spec/spec_helper.rb +42 -4
  39. data/spec/support/dummy_view.rb +7 -0
  40. data/spec/unit/controller_extensions_spec.rb +63 -0
  41. data/spec/unit/crumb_formatter_spec.rb +38 -0
  42. data/spec/unit/options_validator_spec.rb +17 -0
  43. data/spec/unit/translation_spec.rb +22 -0
  44. data/spec/unit/view_extensions/breadcrumb_spec.rb +24 -0
  45. data/spec/unit/view_extensions/breadcrumbs_spec.rb +128 -0
  46. data/spec/unit/view_extensions/has_breadcrumbs_spec.rb +12 -0
  47. data/tasks/console.rake +10 -0
  48. data/tasks/coverage.rake +11 -0
  49. data/tasks/spec.rake +29 -0
  50. metadata +50 -100
  51. data/.rvmrc +0 -28
  52. data/Gemfile.lock +0 -132
  53. data/spec/integration/nested_crumbs_spec.rb +0 -5
  54. data/spec/loaf/controller_extensions_spec.rb +0 -55
  55. data/spec/loaf/crumb_formatter_spec.rb +0 -33
  56. data/spec/loaf/options_validator_spec.rb +0 -29
  57. data/spec/loaf/translation_spec.rb +0 -23
  58. data/spec/loaf/view_extensions_spec.rb +0 -114
  59. data/spec/loaf_spec.rb +0 -5
  60. data/spec/rails_app/app/assets/images/rails.png +0 -0
  61. data/spec/rails_app/app/assets/javascripts/application.js +0 -9
  62. data/spec/rails_app/app/assets/stylesheets/application.css +0 -7
  63. data/spec/rails_app/app/helpers/application_helper.rb +0 -2
  64. data/spec/rails_app/app/models/.gitkeep +0 -0
@@ -1,8 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Loaf
4
- module Configuration
5
-
4
+ class Configuration
6
5
  VALID_ATTRIBUTES = [
7
6
  :locales_path,
8
7
  :style_classes,
@@ -12,9 +11,9 @@ module Loaf
12
11
  :root
13
12
  ]
14
13
 
15
- attr_accessor *VALID_ATTRIBUTES
14
+ attr_accessor(*VALID_ATTRIBUTES)
16
15
 
17
- DEFAULT_LOCALES_PATH = "/"
16
+ DEFAULT_LOCALES_PATH = '/'
18
17
 
19
18
  DEFAULT_STYLE_CLASSES = 'selected'
20
19
 
@@ -26,28 +25,22 @@ module Loaf
26
25
 
27
26
  DEFAULT_ROOT = true
28
27
 
29
- # Sets the Loaf configuration options. Best used by passing a block.
28
+ # Setup this configuration
30
29
  #
31
- # Loaf.configure do |config|
32
- # config.capitalize = true
33
- # end
34
- def configure
35
- yield self
36
- end
37
-
38
- def self.extended(base)
39
- base.setup(self)
40
- end
41
-
42
- def config
43
- VALID_ATTRIBUTES.inject({}) { |hash, k| hash[k] = send(k); hash }
44
- end
45
-
46
- def setup(parent)
30
+ # @api public
31
+ def initialize
47
32
  VALID_ATTRIBUTES.each do |attr|
48
- send("#{attr}=", parent.const_get("DEFAULT_#{attr.to_s.upcase}"))
33
+ send("#{attr}=", self.class.const_get("DEFAULT_#{attr.to_s.upcase}"))
49
34
  end
50
35
  end
51
36
 
37
+ # Convert all properties into hash
38
+ #
39
+ # @return [Hash]
40
+ #
41
+ # @api public
42
+ def to_hash
43
+ VALID_ATTRIBUTES.reduce({}) { |acc, k| acc[k] = send(k); acc }
44
+ end
52
45
  end # Configuration
53
46
  end # Loaf
@@ -2,7 +2,9 @@
2
2
 
3
3
  module Loaf
4
4
  module ControllerExtensions
5
-
5
+ # Module injection
6
+ #
7
+ # @api private
6
8
  def self.included(base)
7
9
  base.extend ClassMethods
8
10
  base.send :include, InstanceMethods
@@ -10,14 +12,16 @@ module Loaf
10
12
  end
11
13
 
12
14
  module ClassMethods
13
-
15
+ # @param [String]
16
+ #
17
+ # @api public
14
18
  def breadcrumb(name, url, options = {})
15
19
  before_filter(options) do |instance|
16
20
  # instance.send(:add_breadcrumb, _normalize_name(name), url)
17
- instance.send(:add_breadcrumb, name, url, options)
21
+ instance.send(:breadcrumb, name, url, options)
18
22
  end
19
23
  end
20
- alias :add_breadcrumb :breadcrumb
24
+ alias_method :add_breadcrumb, :breadcrumb
21
25
 
22
26
  private
23
27
 
@@ -32,16 +36,14 @@ module Loaf
32
36
  name
33
37
  end
34
38
  end
35
-
36
39
  end # ClassMethods
37
40
 
38
41
  module InstanceMethods
39
-
40
42
  # Add collection of nested breadcrumbs.
41
43
  # * <tt>collection</tt> - required collection of object for iteration
42
44
  # * <tt>field</tt> - required object attribute name
43
45
  #
44
- def add_breadcrumbs(collection, field, options={})
46
+ def add_breadcrumbs(collection, field, options = {})
45
47
  namespace = nil
46
48
  item_set = if _check_if_nested collection
47
49
  items = collection.pop
@@ -55,15 +57,28 @@ module Loaf
55
57
  end
56
58
  end
57
59
 
58
- def breadcrumb(name, url, options={})
59
- _breadcrumbs << Loaf::Crumb.new(name, url)
60
+ # Add breadcrumb
61
+ #
62
+ # @param [String] name
63
+ #
64
+ # @param [Object] url
65
+ #
66
+ # @api public
67
+ def breadcrumb(name, url, options = {})
68
+ _breadcrumbs << Loaf::Crumb.new(name, url, options)
60
69
  end
61
- alias :add_breadcrumb :breadcrumb
70
+ alias_method :add_breadcrumb, :breadcrumb
62
71
 
72
+ # Collection of breadcrumbs
73
+ #
74
+ # @api private
63
75
  def _breadcrumbs
64
76
  @_breadcrumbs ||= []
65
77
  end
66
78
 
79
+ # Remove all current breadcrumbs
80
+ #
81
+ # @api public
67
82
  def clear_breadcrumbs
68
83
  _breadcrumbs.clear
69
84
  end
@@ -73,8 +88,6 @@ module Loaf
73
88
  def _check_if_nested(collection)
74
89
  collection.last.is_a? Array
75
90
  end
76
-
77
91
  end # InstanceMethods
78
-
79
92
  end # ControllerExtensions
80
93
  end # Loaf
@@ -2,5 +2,17 @@
2
2
 
3
3
  module Loaf
4
4
  # Basic crumb container
5
- Crumb = Struct.new(:name, :url, :styles)
5
+ class Crumb
6
+ attr_reader :name
7
+
8
+ attr_reader :url
9
+
10
+ attr_reader :force
11
+
12
+ def initialize(name, url, options = {})
13
+ @name = name
14
+ @url = url
15
+ @force = options.fetch(:force) { false }
16
+ end
17
+ end
6
18
  end # Loaf
@@ -1,20 +1,21 @@
1
+ # encoding: utf-8
2
+
1
3
  module Loaf
4
+ # A mixin for formatting crumb name
2
5
  module CrumbFormatter
6
+ # @param [String] name
7
+ # the name to format
8
+ #
9
+ # @api public
10
+ def format_name(name, options = {})
11
+ return if name.nil?
3
12
 
4
- def format_name(crumb, options={})
5
- if !crumb.name.blank?
6
- formatted = crumb.name
7
- formatted = crumb.name.capitalize if options[:capitalize]
8
- formatted = if options[:crumb_length]
9
- truncate(formatted, :length => options[:crumb_length])
10
- else
11
- formatted
12
- end
13
- formatted
14
- else
15
- '[name-error]'
13
+ formatted = name.to_s.dup
14
+ formatted = formatted.capitalize if options[:capitalize]
15
+ if options[:crumb_length]
16
+ formatted = truncate(formatted, length: options[:crumb_length])
16
17
  end
18
+ formatted
17
19
  end
18
-
19
20
  end # CrumbFormatter
20
21
  end # Loaf
@@ -3,12 +3,20 @@
3
3
  require 'loaf/errors'
4
4
 
5
5
  module Loaf
6
+ # A mixin to validate configuration options
6
7
  module OptionsValidator
8
+ # Check if options are valid or not
9
+ #
10
+ # @param [Hash] options
11
+ #
12
+ # @return [Boolean]
13
+ #
14
+ # @api public
7
15
  def valid?(options)
8
16
  valid_options = Loaf::Configuration::VALID_ATTRIBUTES
9
17
  options.each_key do |key|
10
- if !valid_options.include?(key)
11
- raise Loaf::InvalidOptions.new(key, valid_options)
18
+ unless valid_options.include?(key)
19
+ fail Loaf::InvalidOptions.new(key, valid_options)
12
20
  end
13
21
  end
14
22
  true
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  module Loaf
2
4
  module Translation
3
5
  extend self
@@ -7,17 +9,22 @@ module Loaf
7
9
  :breadcrumbs
8
10
  end
9
11
 
10
- # Accepts <tt>:scope</tt> parameter.
11
- def breadcrumb_title(title, options={})
12
+ # Translate breadcrumb title
13
+ #
14
+ # @param [String] :title
15
+ # @param [Hash] options
16
+ # @option options [String] :scope
17
+ # The translation scope
18
+ # @option options [String] :default
19
+ # The default translation
20
+ #
21
+ # @api public
22
+ def breadcrumb_title(title, options = {})
12
23
  defaults = []
13
- parts = title.to_s.split('.', 2)
14
- actions = parts.pop
15
- namespace = parts.pop
16
-
17
- defaults << :"#{self.i18n_scope}.#{title}"
24
+ defaults << :"#{i18n_scope}.#{title}"
18
25
  defaults << options.delete(:default) if options[:default]
19
26
 
20
- options.reverse_merge! :count => 1, :default => defaults
27
+ options.reverse_merge! count: 1, default: defaults
21
28
  I18n.t(title, options)
22
29
  end
23
30
  end # Translation
@@ -1,12 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Loaf
4
- module Version
5
- MAJOR = 0
6
- MINOR = 3
7
- PATCH = 0
8
- BUILD = nil
9
-
10
- STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.');
11
- end
4
+ VERSION = '0.4.0'
12
5
  end # Loaf
@@ -4,43 +4,70 @@ require 'loaf/crumb_formatter'
4
4
  require 'loaf/options_validator'
5
5
 
6
6
  module Loaf
7
+ # A mixin to define view extensions
7
8
  module ViewExtensions
8
9
  include Loaf::CrumbFormatter
9
10
  include Loaf::OptionsValidator
10
11
 
12
+ def initialize(*)
13
+ @_breadcrumbs ||= []
14
+ super
15
+ end
16
+
17
+ # Checks to see if any breadcrumbs have been added
18
+ #
19
+ # @return [Boolean]
20
+ #
21
+ # @api public
22
+ def breadcrumbs?
23
+ _breadcrumbs.present?
24
+ end
25
+
11
26
  # Adds breadcrumbs inside view.
12
27
  #
13
- def breadcrumb(name, url)
14
- _breadcrumbs.push Loaf::Crumb.new(name, url)
28
+ # @param [String] name
29
+ # the breadcrumb name
30
+ # @param [Object] url
31
+ # the breadcrumb url
32
+ # @param [Hash] options
33
+ # the breadcrumb options
34
+ #
35
+ # @api public
36
+ def breadcrumb(name, url, options = {})
37
+ _breadcrumbs << Loaf::Crumb.new(name, url, options)
15
38
  end
16
- alias :add_breadcrumb :breadcrumb
39
+ alias_method :add_breadcrumb, :breadcrumb
17
40
 
18
41
  # Renders breadcrumbs inside view.
19
42
  #
20
- def breadcrumbs(options={}, &block)
21
- #builder = Loaf::Builder.new(options)
22
- valid? options
23
- options = Loaf.config.merge(options)
43
+ # @param [Hash] options
44
+ #
45
+ # @api public
46
+ def breadcrumbs(options = {}, &block)
47
+ # builder = Loaf::Builder.new(options)
48
+ return enum_for(:breadcrumbs) unless block_given?
49
+ valid?(options)
50
+ options = Loaf.configuration.to_hash.merge(options)
24
51
  _breadcrumbs.each do |crumb|
25
- name = format_name crumb, options
26
-
27
- url = url_for _process_url_for(crumb.url)
28
-
29
- styles = current_page?(url) ? "#{options[:style_classes]}" : ''
30
-
52
+ name = format_name(crumb.name, options)
53
+ url = url_for(_process_url_for(crumb.url))
54
+ styles = ''
55
+ if current_page?(url) || crumb.force
56
+ styles << "#{options[:style_classes]}"
57
+ end
31
58
  block.call(name, url, styles)
32
59
  end
33
60
  end
34
61
 
35
62
  private
36
63
 
64
+ # @api private
37
65
  def _process_url_for(url)
38
66
  if url.is_a?(String) || url.is_a?(Symbol)
39
- return send url
67
+ return respond_to?(url) ? send(url) : url
40
68
  else
41
69
  return url
42
70
  end
43
71
  end
44
-
45
72
  end # ViewExtensions
46
73
  end # Loaf
@@ -1,28 +1,21 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
4
  require 'loaf/version'
4
5
 
5
6
  Gem::Specification.new do |s|
6
- s.name = "loaf"
7
- s.version = Loaf::Version::STRING.dup
8
- s.authors = ["Piotr Murach"]
7
+ s.name = 'loaf'
8
+ s.version = Loaf::VERSION.dup
9
+ s.authors = ['Piotr Murach']
9
10
  s.email = [""]
10
- s.homepage = "https://github.com/peter-murach/loaf"
11
- s.summary = %q{Loaf is a breadcrumb managing gem.}
12
- s.description = %q{Loaf helps you manage breadcrumbs in your rails app. It aims to handle crumb data through easy dsl and expose it through view helpers without any assumptions about markup.}
13
-
14
- s.rubyforge_project = "tytus"
11
+ s.homepage = 'https://github.com/peter-murach/loaf'
12
+ s.summary = %q{Loaf manages and displays breadcrumb trails in your Rails application.}
13
+ s.description = %q{Loaf manages and displays breadcrumb trails in your Rails app. It aims to handle breadcrumb data through easy dsl and expose it through view helpers without any assumptions about markup.}
15
14
 
16
15
  s.files = `git ls-files`.split("\n")
17
16
  s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
18
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
18
  s.require_paths = ["lib"]
20
19
 
21
- s.add_dependency 'rails'
22
-
23
- s.add_development_dependency 'rails', '~> 3.1'
24
- s.add_development_dependency 'sqlite3'
25
- s.add_development_dependency 'rspec-rails'
26
- s.add_development_dependency 'capybara'
27
- s.add_development_dependency 'bundler'
20
+ s.add_dependency 'rails', '>= 3.1'
28
21
  end
@@ -1,13 +1,12 @@
1
- require 'spec_helper'
1
+ # encoding: utf-8
2
2
 
3
- describe 'setting configuration options' do
3
+ require 'spec_helper'
4
4
 
5
- context 'setting default css style for current crumb' do
6
- it "contains 'selected' inside the breadcrumb markup" do
7
- visit root_path
8
- within '#breadcrumbs' do
9
- page.should have_selector('.selected')
10
- end
5
+ RSpec.describe 'setting configuration options' do
6
+ it "contains 'selected' inside the breadcrumb markup" do
7
+ visit posts_path
8
+ within '#breadcrumbs' do
9
+ expect(page).to have_selector('.selected')
11
10
  end
12
11
  end
13
12
  end
@@ -1,43 +1,46 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
- describe "crumbs routing" do
5
+ RSpec.describe "crumbs routing" do
4
6
  include ActionView::TestCase::Behavior
5
7
 
6
- context 'setting home breadcrumb' do
7
- it 'should inherit crumb for the root path' do
8
- visit root_path
9
- within '#breadcrumbs' do
10
- page.should have_content("Home")
11
- end
8
+ it "doens't show empty breadcrumbs" do
9
+ visit root_path
10
+ expect(page).to_not have_content("breadcrumbs")
11
+ end
12
+
13
+ it "inherits controller breadcrumb and adds index action breadcrumb" do
14
+ visit posts_path
15
+ within '#breadcrumbs' do
16
+ expect(page.html).to include('<a href="/">Home</a>')
17
+ expect(page.html).to include('<a href="/posts">All Posts</a>')
12
18
  end
13
19
  end
14
20
 
15
- context 'inheriting breadcrumbs setup' do
16
- it "should inherit root crumb for index action posts#index" do
17
- visit posts_path
18
- within '#breadcrumbs' do
19
- page.should have_content 'Home'
20
- page.should have_content 'All Posts'
21
- page.should_not have_content 'New Post'
22
- end
21
+ it 'filters out controller breadcrumb and adds new action breadcrumb' do
22
+ visit new_post_path
23
+ within '#breadcrumbs' do
24
+ expect(page).to_not have_content('Home')
25
+ expect(page).to have_content('New Post')
23
26
  end
27
+ end
24
28
 
25
- it 'should inherit and add new action specific breadcrumb' do
26
- visit new_post_path
27
- within '#breadcrumbs' do
28
- page.should have_content 'All Posts'
29
- page.should have_content 'New Post'
30
- end
29
+ it "adds breadcrumb in view with path variable" do
30
+ visit post_path(1)
31
+ within '#breadcrumbs' do
32
+ expect(page.html).to include('<a href="/posts/1">Show Post in view</a>')
31
33
  end
32
34
  end
33
35
 
34
- context 'adding breadcrumbs within view' do
35
- it 'should append view specified breadcrumb' do
36
- visit posts_path
37
- within '#breadcrumbs' do
38
- page.should have_content 'All Posts'
39
- page.should have_content 'View Post'
40
- end
36
+ it 'should be current when forced' do
37
+ visit new_post_path
38
+ click_button "Create"
39
+
40
+ expect(page.current_path).to eq(posts_path)
41
+ within '#breadcrumbs' do
42
+ expect(page).to have_content('New Post')
43
+ expect(page).to have_selector('.selected')
41
44
  end
42
45
  end
43
46
  end