loaf 0.5.0 → 0.6.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -3
  3. data/.rspec +1 -0
  4. data/.travis.yml +30 -12
  5. data/Appraisals +27 -9
  6. data/CHANGELOG.md +59 -11
  7. data/Gemfile +11 -11
  8. data/Gemfile.lock +182 -0
  9. data/README.md +120 -56
  10. data/assets/loaf_logo.png +0 -0
  11. data/bin/appraisal +16 -0
  12. data/bin/rake +16 -0
  13. data/gemfiles/rails3.2.gemfile +15 -13
  14. data/gemfiles/rails4.0.gemfile +13 -12
  15. data/gemfiles/rails4.1.gemfile +14 -13
  16. data/gemfiles/rails4.2.gemfile +14 -13
  17. data/gemfiles/rails5.0.gemfile +22 -0
  18. data/gemfiles/rails5.1.gemfile +22 -0
  19. data/lib/loaf.rb +2 -22
  20. data/lib/loaf/breadcrumb.rb +30 -0
  21. data/lib/loaf/configuration.rb +7 -8
  22. data/lib/loaf/controller_extensions.rb +13 -28
  23. data/lib/loaf/crumb.rb +5 -4
  24. data/lib/loaf/crumb_formatter.rb +3 -1
  25. data/lib/loaf/errors.rb +1 -3
  26. data/lib/loaf/options_validator.rb +2 -2
  27. data/lib/loaf/railtie.rb +19 -13
  28. data/lib/loaf/translation.rb +1 -1
  29. data/lib/loaf/version.rb +1 -3
  30. data/lib/loaf/view_extensions.rb +69 -18
  31. data/loaf.gemspec +20 -13
  32. data/spec/integration/{crumbs_routing_spec.rb → breadcrumb_trail_spec.rb} +19 -12
  33. data/spec/rails_app/app/controllers/application_controller.rb +2 -0
  34. data/spec/rails_app/app/controllers/posts_controller.rb +1 -4
  35. data/spec/rails_app/app/views/layouts/_breadcrumbs.html.erb +7 -5
  36. data/spec/rails_app/app/views/layouts/application.html.erb +0 -2
  37. data/spec/rails_app/config/environments/test.rb +1 -1
  38. data/spec/rails_app/config/secrets.yml +22 -0
  39. data/spec/spec_helper.rb +3 -3
  40. data/spec/support/dummy_controller.rb +9 -0
  41. data/spec/support/dummy_view.rb +42 -2
  42. data/spec/unit/configuration_spec.rb +35 -0
  43. data/spec/unit/controller_extensions_spec.rb +5 -14
  44. data/spec/unit/generators/install_generator_spec.rb +2 -1
  45. data/spec/unit/view_extensions/breadcrumb_trail_spec.rb +232 -0
  46. metadata +65 -31
  47. data/.ruby-version +0 -1
  48. data/init.rb +0 -3
  49. data/lib/loaf/builder.rb +0 -38
  50. data/spec/rails_app/.gitignore +0 -5
  51. data/spec/rails_app/lib/assets/.gitkeep +0 -0
  52. data/spec/rails_app/lib/tasks/.gitkeep +0 -0
  53. data/spec/rails_app/script/rails +0 -6
  54. data/spec/unit/view_extensions/breadcrumbs_spec.rb +0 -128
@@ -0,0 +1,22 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "ammeter", "~> 1.1.4"
6
+ gem "appraisal", "~> 2.2.0"
7
+ gem "yard", "~> 0.9.9"
8
+ gem "capybara", "~> 2.15.4"
9
+ gem "rspec-rails", "~> 3.6.1"
10
+ gem "nokogiri", "~> 1.6.8"
11
+ gem "public_suffix", "~> 2.0.5"
12
+ gem "sqlite3", "~> 1.3.13", platforms: :ruby
13
+ gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.23", platforms: :jruby
14
+ gem "rails", "~> 5.0.6"
15
+
16
+ group :metrics do
17
+ gem "coveralls", "0.8.17"
18
+ gem "simplecov", "~> 0.12.0"
19
+ gem "yardstick", "~> 0.9.9"
20
+ end
21
+
22
+ gemspec path: "../"
@@ -0,0 +1,22 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "ammeter", "~> 1.1.4"
6
+ gem "appraisal", "~> 2.2.0"
7
+ gem "yard", "~> 0.9.9"
8
+ gem "capybara", "~> 2.15.4"
9
+ gem "rspec-rails", "~> 3.6.1"
10
+ gem "nokogiri", "~> 1.6.8"
11
+ gem "public_suffix", "~> 2.0.5"
12
+ gem "sqlite3", "~> 1.3.13", platforms: :ruby
13
+ gem "activerecord-jdbcsqlite3-adapter", "~> 1.3.23", platforms: :jruby
14
+ gem "rails", "~> 5.1.4"
15
+
16
+ group :metrics do
17
+ gem "coveralls", "0.8.17"
18
+ gem "simplecov", "~> 0.12.0"
19
+ gem "yardstick", "~> 0.9.9"
20
+ end
21
+
22
+ gemspec path: "../"
data/lib/loaf.rb CHANGED
@@ -1,15 +1,5 @@
1
- # encoding: utf-8
2
-
3
- require 'loaf/configuration'
4
- require 'loaf/errors'
5
- require 'loaf/railtie'
6
- require 'loaf/crumb'
7
- require 'loaf/builder'
8
- require 'loaf/translation'
9
- require 'loaf/controller_extensions'
10
- require 'loaf/view_extensions'
11
- require 'loaf/crumb_formatter'
12
- require 'loaf/options_validator'
1
+ require_relative 'loaf/configuration'
2
+ require_relative 'loaf/railtie'
13
3
 
14
4
  module Loaf
15
5
  # Set global configuration
@@ -34,14 +24,4 @@ module Loaf
34
24
  def self.configure
35
25
  yield configuration
36
26
  end
37
-
38
- if defined? Rails::Railtie
39
- require 'loaf/railtie'
40
- else
41
- autoload :ControllerExtensions, 'loaf/controller_extensions'
42
- autoload :Helpers, 'loaf/view_extensions'
43
-
44
- ::ActionController::Base.send :include, Loaf::ControllerExtensions
45
- ::ActionController::Base.helper Loaf::ViewExtensions
46
- end
47
27
  end # Loaf
@@ -0,0 +1,30 @@
1
+ module Loaf
2
+ # A container for breadcrumb values
3
+ # @api public
4
+ class Breadcrumb
5
+ attr_reader :name
6
+
7
+ attr_reader :path
8
+ alias url path
9
+
10
+ def self.[](*args)
11
+ new(*args)
12
+ end
13
+
14
+ def initialize(name, path, current)
15
+ @name = name
16
+ @path = path
17
+ @current = current
18
+ freeze
19
+ end
20
+
21
+ def current?
22
+ @current
23
+ end
24
+
25
+ def to_ary
26
+ [@name, @path, @current]
27
+ end
28
+ alias to_a to_ary
29
+ end # Breadcrumb
30
+ end # Loaf
@@ -1,15 +1,12 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Loaf
4
4
  class Configuration
5
5
  VALID_ATTRIBUTES = [
6
6
  :locales_path,
7
- :style_classes,
8
7
  :crumb_length,
9
- :last_crumb_linked,
10
- :capitalize,
11
- :root
12
- ]
8
+ :capitalize
9
+ ].freeze
13
10
 
14
11
  attr_accessor(*VALID_ATTRIBUTES)
15
12
 
@@ -28,9 +25,11 @@ module Loaf
28
25
  # Setup this configuration
29
26
  #
30
27
  # @api public
31
- def initialize
28
+ def initialize(attributes = {})
32
29
  VALID_ATTRIBUTES.each do |attr|
33
- send("#{attr}=", self.class.const_get("DEFAULT_#{attr.to_s.upcase}"))
30
+ default = self.class.const_get("DEFAULT_#{attr.to_s.upcase}")
31
+ attr_value = attributes.fetch(attr) { default }
32
+ send("#{attr}=", attr_value)
34
33
  end
35
34
  end
36
35
 
@@ -1,4 +1,6 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'crumb'
2
4
 
3
5
  module Loaf
4
6
  module ControllerExtensions
@@ -19,16 +21,23 @@ module Loaf
19
21
  # @api public
20
22
  def breadcrumb(name, url, options = {})
21
23
  normalizer = method(:_normalize_name)
22
- before_filter(options) do |instance|
24
+ send(_filter_name, options) do |instance|
23
25
  normalized_name = normalizer.call(name, instance)
24
26
  normalized_url = normalizer.call(url, instance)
25
27
  instance.send(:breadcrumb, normalized_name, normalized_url, options)
26
28
  end
27
29
  end
28
- alias_method :add_breadcrumb, :breadcrumb
30
+ alias add_breadcrumb breadcrumb
29
31
 
30
32
  private
31
33
 
34
+ # Choose available filter name
35
+ #
36
+ # @api private
37
+ def _filter_name
38
+ respond_to?(:before_action) ? :before_action : :before_filter
39
+ end
40
+
32
41
  # @api private
33
42
  def _normalize_name(name, instance)
34
43
  case name
@@ -42,24 +51,6 @@ module Loaf
42
51
  end # ClassMethods
43
52
 
44
53
  module InstanceMethods
45
- # Add collection of nested breadcrumbs.
46
- # * <tt>collection</tt> - required collection of object for iteration
47
- # * <tt>field</tt> - required object attribute name
48
- #
49
- def add_breadcrumbs(collection, field, options = {})
50
- namespace = nil
51
- item_set = if _check_if_nested collection
52
- items = collection.pop
53
- namespace = collection
54
- items
55
- else
56
- collection
57
- end
58
- item_set.each do |item|
59
- add_breadcrumb item.send(field.to_sym), [ namespace, item ].flatten.compact
60
- end
61
- end
62
-
63
54
  # Add breadcrumb in controller as instance method
64
55
  #
65
56
  # @param [String] name
@@ -70,7 +61,7 @@ module Loaf
70
61
  def breadcrumb(name, url, options = {})
71
62
  _breadcrumbs << Loaf::Crumb.new(name, url, options)
72
63
  end
73
- alias_method :add_breadcrumb, :breadcrumb
64
+ alias add_breadcrumb breadcrumb
74
65
 
75
66
  # Collection of breadcrumbs
76
67
  #
@@ -85,12 +76,6 @@ module Loaf
85
76
  def clear_breadcrumbs
86
77
  _breadcrumbs.clear
87
78
  end
88
-
89
- private
90
-
91
- def _check_if_nested(collection)
92
- collection.last.is_a? Array
93
- end
94
79
  end # InstanceMethods
95
80
  end # ControllerExtensions
96
81
  end # Loaf
data/lib/loaf/crumb.rb CHANGED
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Loaf
4
4
  # Basic crumb container
@@ -7,12 +7,13 @@ module Loaf
7
7
 
8
8
  attr_reader :url
9
9
 
10
- attr_reader :force
10
+ attr_reader :match
11
11
 
12
12
  def initialize(name, url, options = {})
13
13
  @name = name
14
14
  @url = url
15
- @force = options.fetch(:force) { false }
15
+ @match = options.delete(:match) { :inclusive }
16
+ freeze
16
17
  end
17
- end
18
+ end # Crumb
18
19
  end # Loaf
@@ -1,4 +1,6 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'translation'
2
4
 
3
5
  module Loaf
4
6
  # A mixin for formatting crumb name
data/lib/loaf/errors.rb CHANGED
@@ -1,7 +1,6 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Loaf #:nodoc:
4
-
5
4
  # Default Loaf error for all custom errors.
6
5
  #
7
6
  class LoafError < StandardError
@@ -28,5 +27,4 @@ module Loaf #:nodoc:
28
27
  )
29
28
  end
30
29
  end
31
-
32
30
  end # Loaf
@@ -1,6 +1,6 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'loaf/errors'
3
+ require_relative 'errors'
4
4
 
5
5
  module Loaf
6
6
  # A mixin to validate configuration options
data/lib/loaf/railtie.rb CHANGED
@@ -3,27 +3,33 @@
3
3
  require 'action_controller'
4
4
  require 'action_view'
5
5
 
6
- module Loaf
7
- if defined? Rails::Railtie
8
- class Railtie < Rails::Railtie
9
- initializer "loaf.extend_action_controller_base" do |app|
10
- ActiveSupport.on_load :action_controller do
11
- Loaf::Railtie.insert_controller
12
- Loaf::Railtie.insert_view
13
- end
14
- end
15
- end
16
- end
6
+ require_relative 'controller_extensions'
7
+ require_relative 'view_extensions'
17
8
 
18
- class Railtie
9
+ module Loaf
10
+ class RailtieHelpers
19
11
  class << self
20
12
  def insert_view
21
13
  ActionController::Base.helper Loaf::ViewExtensions
22
14
  end
15
+
23
16
  def insert_controller
24
17
  ActionController::Base.send :include, Loaf::ControllerExtensions
25
18
  end
26
19
  end
27
- end # Railtie
20
+ end # RailtieHelpers
28
21
 
22
+ if defined?(Rails::Railtie)
23
+ class Railtie < Rails::Railtie
24
+ initializer "loaf.extend_action_controller_base" do |app|
25
+ ActiveSupport.on_load :action_controller do
26
+ Loaf::RailtieHelpers.insert_controller
27
+ Loaf::RailtieHelpers.insert_view
28
+ end
29
+ end
30
+ end
31
+ else
32
+ Loaf::RailtieHelpers.insert_controller
33
+ Loaf::RailtieHelpers.insert_view
34
+ end
29
35
  end # Loaf
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Loaf
4
4
  module Translation
data/lib/loaf/version.rb CHANGED
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module Loaf
4
- VERSION = '0.5.0'
2
+ VERSION = '0.6.0'
5
3
  end # Loaf
@@ -1,7 +1,9 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'loaf/crumb_formatter'
4
- require 'loaf/options_validator'
3
+ require_relative 'breadcrumb'
4
+ require_relative 'crumb'
5
+ require_relative 'crumb_formatter'
6
+ require_relative 'options_validator'
5
7
 
6
8
  module Loaf
7
9
  # A mixin to define view extensions
@@ -36,37 +38,86 @@ module Loaf
36
38
  def breadcrumb(name, url, options = {})
37
39
  _breadcrumbs << Loaf::Crumb.new(name, url, options)
38
40
  end
39
- alias_method :add_breadcrumb, :breadcrumb
41
+ alias add_breadcrumb breadcrumb
40
42
 
41
43
  # Renders breadcrumbs inside view.
42
44
  #
43
45
  # @param [Hash] options
44
46
  #
45
47
  # @api public
46
- def breadcrumbs(options = {}, &block)
47
- # builder = Loaf::Builder.new(options)
48
- return enum_for(:breadcrumbs) unless block_given?
48
+ def breadcrumb_trail(options = {})
49
+ return enum_for(:breadcrumb_trail) unless block_given?
50
+
49
51
  valid?(options)
50
52
  options = Loaf.configuration.to_hash.merge(options)
51
53
  _breadcrumbs.each do |crumb|
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
58
- block.call(name, url, styles)
54
+ name = format_name(crumb.name, options)
55
+ path = url_for(_expand_url(crumb.url))
56
+ current = current_crumb?(path, crumb.match)
57
+
58
+ yield(Loaf::Breadcrumb[name, path, current])
59
+ end
60
+ end
61
+
62
+ # Check if breadcrumb is current based on the pattern
63
+ #
64
+ # @param [String] path
65
+ # @param [Object] pattern
66
+ # the pattern to match on
67
+ #
68
+ # @api public
69
+ def current_crumb?(path, pattern = :inclusive)
70
+ return false unless request.get? || request.head?
71
+
72
+ origin_path = URI.parser.unescape(path).force_encoding(Encoding::BINARY)
73
+
74
+ request_uri = request.fullpath
75
+ request_uri = URI.parser.unescape(request_uri)
76
+ request_uri.force_encoding(Encoding::BINARY)
77
+
78
+ # strip away trailing slash
79
+ if origin_path.start_with?('/') && origin_path != '/'
80
+ origin_path.chomp!('/')
81
+ request_uri.chomp!('/')
82
+ end
83
+
84
+ if %r{^\w+://} =~ origin_path
85
+ origin_path.chomp!('/')
86
+ request_uri.insert(0, "#{request.protocol}#{request.host_with_port}")
87
+ end
88
+
89
+ case pattern
90
+ when :inclusive
91
+ !request_uri.match(/^#{Regexp.escape(origin_path)}(\/.*|\?.*)?$/).nil?
92
+ when :exclusive
93
+ !request_uri.match(/^#{Regexp.escape(origin_path)}\/?(\?.*)?$/).nil?
94
+ when :exact
95
+ request_uri == origin_path
96
+ when :force
97
+ true
98
+ when Regexp
99
+ !request_uri.match(pattern).nil?
100
+ when Hash
101
+ query_params = URI.encode_www_form(pattern)
102
+ !request_uri.match(/^#{Regexp.escape(origin_path)}\/?(\?.*)?.*?#{query_params}.*$/).nil?
103
+ else
104
+ raise ArgumentError, "Unknown `:#{pattern}` match option!"
59
105
  end
60
106
  end
61
107
 
62
108
  private
63
109
 
110
+ # Expand url in the current context of the view
111
+ #
64
112
  # @api private
65
- def _process_url_for(url)
66
- if url.is_a?(String) || url.is_a?(Symbol)
67
- return respond_to?(url) ? send(url) : url
113
+ def _expand_url(url)
114
+ case url
115
+ when String, Symbol
116
+ respond_to?(url) ? send(url) : url
117
+ when Proc
118
+ url.call(self)
68
119
  else
69
- return url
120
+ url
70
121
  end
71
122
  end
72
123
  end # ViewExtensions