loaf 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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