loaf 0.5.0 → 0.6.0

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