blocks 3.0.2 → 4.0.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 (58) hide show
  1. checksums.yaml +5 -5
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +61 -17
  4. data/CHANGELOG.rdoc +27 -0
  5. data/Gemfile +11 -10
  6. data/Guardfile +1 -0
  7. data/README.md +2 -0
  8. data/bin/deploy_docs +1 -1
  9. data/blocks.gemspec +3 -1
  10. data/docs/_includes/configuration.md +3 -6
  11. data/docs/_includes/defining.md +7 -7
  12. data/docs/_includes/{introduction.md → features.md} +2 -2
  13. data/docs/_includes/helper-blocks.md +5 -0
  14. data/docs/_includes/helper-blocks/content_tag.md +44 -0
  15. data/docs/_includes/installation.md +16 -2
  16. data/docs/_includes/overview.md +21 -0
  17. data/docs/_includes/templating.md +1 -1
  18. data/docs/_includes/templating/bootstrap_4_cards.md +9 -9
  19. data/docs/_layouts/slate.html +11 -9
  20. data/docs/index.md +3 -1
  21. data/gemfiles/Gemfile.rails-3-0-stable +1 -0
  22. data/gemfiles/Gemfile.rails-3-1-stable +1 -0
  23. data/gemfiles/Gemfile.rails-3-2-stable +1 -0
  24. data/gemfiles/Gemfile.rails-4-0-stable +2 -1
  25. data/gemfiles/Gemfile.rails-4-1-stable +2 -1
  26. data/gemfiles/Gemfile.rails-4-2-stable +2 -1
  27. data/gemfiles/Gemfile.rails-5-0-stable +4 -3
  28. data/gemfiles/Gemfile.rails-5-1-stable +4 -3
  29. data/gemfiles/Gemfile.rails-5-2-stable +13 -0
  30. data/lib/blocks.rb +37 -29
  31. data/lib/blocks/builders/block_definition.rb +45 -43
  32. data/lib/blocks/builders/builder.rb +96 -60
  33. data/lib/blocks/builders/hook_definition.rb +19 -4
  34. data/lib/blocks/engine.rb +14 -0
  35. data/lib/blocks/helpers/controller_extensions.rb +13 -0
  36. data/lib/blocks/helpers/haml_capture.rb +44 -0
  37. data/lib/blocks/{action_view_extensions → helpers}/view_extensions.rb +10 -4
  38. data/lib/blocks/renderers/adjacent_blocks_renderer.rb +9 -7
  39. data/lib/blocks/renderers/block_placeholder.rb +2 -0
  40. data/lib/blocks/renderers/block_renderer.rb +26 -5
  41. data/lib/blocks/renderers/block_with_hooks_renderer.rb +29 -19
  42. data/lib/blocks/renderers/collection_renderer.rb +18 -6
  43. data/lib/blocks/renderers/nesting_blocks_renderer.rb +9 -11
  44. data/lib/blocks/renderers/partial_renderer.rb +16 -14
  45. data/lib/blocks/renderers/renderer.rb +9 -24
  46. data/lib/blocks/renderers/runtime_context.rb +175 -147
  47. data/lib/blocks/renderers/wrapper_renderer.rb +21 -10
  48. data/lib/blocks/utilities/configurator.rb +30 -6
  49. data/lib/blocks/utilities/hash_with_caller.rb +36 -32
  50. data/lib/blocks/utilities/hash_with_render_strategy.rb +67 -19
  51. data/lib/blocks/utilities/options_set.rb +38 -63
  52. data/lib/blocks/version.rb +3 -1
  53. metadata +23 -22
  54. data/docs/_includes/wip.md +0 -34
  55. data/lib/blocks/experimental/builder_permissions.rb +0 -52
  56. data/lib/blocks/experimental/invalid_permissions_handler.rb +0 -27
  57. data/lib/blocks/renderers/abstract_renderer.rb +0 -69
  58. data/lib/blocks/utilities/dynamic_configuration.rb +0 -71
@@ -23,15 +23,13 @@ under the License.
23
23
  {% assign images_url = '/' | prepend: site.images_dir | prepend: '/' | prepend: site_url %}
24
24
  <html>
25
25
  <head>
26
- <!-- Global Site Tag (gtag.js) - Google Analytics -->
27
- <script async src="https://www.googletagmanager.com/gtag/js?id=UA-104699666-1"></script>
28
- <script>
29
- window.dataLayer = window.dataLayer || [];
30
- function gtag(){dataLayer.push(arguments)};
31
- gtag('js', new Date());
32
-
33
- gtag('config', 'UA-104699666-1');
34
- </script>
26
+ <!-- Google Tag Manager -->
27
+ <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
28
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
29
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
30
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
31
+ })(window,document,'script','dataLayer','GTM-KG9MQ69');</script>
32
+ <!-- End Google Tag Manager -->
35
33
 
36
34
  <meta charset="utf-8">
37
35
  <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
@@ -42,6 +40,10 @@ under the License.
42
40
  </head>
43
41
 
44
42
  <body class="{{ page_classes }}" data-languages='{{ language_tabs | jsonify }}'>
43
+ <!-- Google Tag Manager (noscript) -->
44
+ <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-KG9MQ69"
45
+ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
46
+ <!-- End Google Tag Manager (noscript) -->
45
47
  <a href="#" id="nav-button">
46
48
  <span>
47
49
  NAV
@@ -10,14 +10,16 @@ toc_footers:
10
10
  - <a href='https://github.com/tripit/slate'>Documentation Powered by Slate</a>
11
11
 
12
12
  includes:
13
- - introduction
13
+ - features
14
14
  - installation
15
+ - overview
15
16
  - defining
16
17
  - rendering
17
18
  - hooks
18
19
  - wrappers
19
20
  - skipping
20
21
  - reserved-keywords
22
+ - helper-blocks
21
23
  - templating
22
24
  - configuration
23
25
  - custom-builders
@@ -9,6 +9,7 @@ gem "public_suffix", "~> 1.4.6"
9
9
  gem "mime-types", "< 3.0"
10
10
  gem "rack", "< 2.0"
11
11
  gem "rspec", "~> 3.0.0"
12
+ gem "rspec-its", "~> 1.2.0"
12
13
  gem "rails", github: "rails/rails", branch: "3-0-stable"
13
14
  gem "shoulda-matchers", "~> 2.0"
14
15
  gem 'test-unit', '~> 3.0'
@@ -9,6 +9,7 @@ gem "public_suffix", "~> 1.4.6"
9
9
  gem "mime-types", "< 3.0"
10
10
  gem "rack", "< 2.0"
11
11
  gem "rspec", "~> 3.0.0"
12
+ gem "rspec-its", "~> 1.2.0"
12
13
  gem "rails", github: "rails/rails", branch: "3-1-stable"
13
14
  gem "shoulda-matchers", "~> 2.0"
14
15
  gem 'test-unit', '~> 3.0'
@@ -9,6 +9,7 @@ gem "public_suffix", "~> 1.4.6"
9
9
  gem "mime-types", "< 3.0"
10
10
  gem "rack", "< 2.0"
11
11
  gem "rspec", "~> 3.0.0"
12
+ gem "rspec-its", "~> 1.2.0"
12
13
  gem "rails", github: "rails/rails", branch: "3-2-stable"
13
14
  gem "shoulda-matchers", "~> 2.0"
14
15
  gem 'test-unit', '~> 3.0'
@@ -9,6 +9,7 @@ gem "public_suffix", "~> 1.4.6"
9
9
  gem "mime-types", "< 3.0"
10
10
  gem "rack", "< 2.0"
11
11
  gem "rspec", "~> 3.0.0"
12
+ gem "rspec-its", "~> 1.2.0"
12
13
  gem "rails", github: "rails/rails", branch: "4-0-stable"
13
- gem "shoulda-matchers", "~> 2.0"
14
+ gem "shoulda-matchers", "3.1.3"
14
15
  gem "haml", "4.0.4"
@@ -9,6 +9,7 @@ gem "public_suffix", "~> 1.4.6"
9
9
  gem "mime-types", "< 3.0"
10
10
  gem "rack", "< 2.0"
11
11
  gem "rspec", "~> 3.0.0"
12
+ gem "rspec-its", "~> 1.2.0"
12
13
  gem "rails", github: "rails/rails", branch: "4-1-stable"
13
- gem "shoulda-matchers", "~> 2.0"
14
+ gem "shoulda-matchers", "3.1.3"
14
15
  gem "haml", "4.0.4"
@@ -9,6 +9,7 @@ gem "public_suffix", "~> 1.4.6"
9
9
  gem "mime-types", "< 3.0"
10
10
  gem "rack", "< 2.0"
11
11
  gem "rspec", "~> 3.0.0"
12
+ gem "rspec-its", "~> 1.2.0"
12
13
  gem "rails", github: "rails/rails", branch: "4-2-stable"
13
- gem "shoulda-matchers", "~> 2.0"
14
+ gem "shoulda-matchers", "3.1.3"
14
15
  gem "haml", "4.0.4"
@@ -2,11 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec path: ".."
4
4
 
5
- # Requires min Ruby version 2.2.2
5
+ # Requires min Ruby version 2.3
6
6
 
7
- gem "nokogiri", "1.6.8.1"
7
+ gem "nokogiri", "1.10.7"
8
8
  gem "capybara"
9
9
  gem "rspec", "~> 3.6.0"
10
+ gem "rspec-its", "~> 1.2.0"
10
11
  gem "rails", github: "rails/rails", branch: "5-0-stable"
11
- gem "shoulda-matchers", "~> 2.0"
12
+ gem "shoulda-matchers", "3.1.3"
12
13
  gem "haml", "~> 5.0.0"
@@ -2,11 +2,12 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec path: ".."
4
4
 
5
- # Requires min Ruby version 2.2.2
5
+ # Requires min Ruby version 2.3
6
6
 
7
- gem "nokogiri", "1.6.8.1"
7
+ gem "nokogiri", "1.10.7"
8
8
  gem "capybara"
9
9
  gem "rspec", "~> 3.6.0"
10
+ gem "rspec-its", "~> 1.2.0"
10
11
  gem "rails", github: "rails/rails", branch: "5-1-stable"
11
- gem "shoulda-matchers", "~> 2.0"
12
+ gem "shoulda-matchers", "3.1.3"
12
13
  gem "haml", "~> 5.0.0"
@@ -0,0 +1,13 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec path: ".."
4
+
5
+ # Requires min Ruby version 2.3
6
+
7
+ gem "nokogiri", "1.10.7"
8
+ gem "capybara"
9
+ gem "rspec", "~> 3.6.0"
10
+ gem "rspec-its", "~> 1.2.0"
11
+ gem "rails", github: "rails/rails", branch: "5-2-stable"
12
+ gem "shoulda-matchers", "3.1.3"
13
+ gem "haml", "~> 5.0.0"
@@ -1,47 +1,55 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/core_ext/hash'
2
- require 'active_support/hash_with_indifferent_access'
3
- require 'blocks/action_view_extensions/view_extensions'
4
+ require 'blocks/helpers/view_extensions'
5
+ require 'blocks/helpers/controller_extensions'
4
6
 
5
7
  module Blocks
6
8
  extend ActiveSupport::Autoload
7
9
 
10
+ # The following classes have no direct references when loading the rest
11
+ # of the Blocks classes so they must be eager loaded to prevent them
12
+ # from having to be loaded during the request
13
+ # (http://blog.plataformatec.com.br/2012/08/eager-loading-for-greater-good/)
8
14
  eager_autoload do
15
+ autoload_under 'builders' do
16
+ autoload :BlockDefinition
17
+ end
18
+
9
19
  autoload_under 'renderers' do
10
- autoload :Renderer
11
20
  autoload :RuntimeContext
12
- autoload :AbstractRenderer
13
- autoload :PartialRenderer
14
- autoload :BlockWithHooksRenderer
15
- autoload :AdjacentBlocksRenderer
16
- autoload :NestingBlocksRenderer
17
- autoload :CollectionRenderer
18
- autoload :WrapperRenderer
19
- autoload :BlockRenderer
20
21
  autoload :BlockPlaceholder
21
22
  end
23
+ end
22
24
 
23
- autoload_under 'builders' do
24
- autoload :HookDefinition
25
- autoload :BlockDefinition
26
- autoload :Builder
27
- end
25
+ autoload_under 'renderers' do
26
+ autoload :Renderer
27
+ autoload :PartialRenderer
28
+ autoload :BlockWithHooksRenderer
29
+ autoload :AdjacentBlocksRenderer
30
+ autoload :NestingBlocksRenderer
31
+ autoload :CollectionRenderer
32
+ autoload :WrapperRenderer
33
+ autoload :BlockRenderer
34
+ end
28
35
 
29
- autoload_under 'utilities' do
30
- autoload :DynamicConfiguration
31
- autoload :Configurator
32
- autoload :OptionsSet
33
- autoload :HashWithRenderStrategy
34
- autoload :HashWithCaller
35
- end
36
+ autoload_under 'builders' do
37
+ autoload :Builder
38
+ autoload :HookDefinition
36
39
  end
37
40
 
38
- # WIP
39
- # autoload_under 'experimental' do
40
- # autoload :BuilderPermissions
41
- # autoload :InvalidPermissionsHandler
42
- # end
41
+ autoload_under 'utilities' do
42
+ autoload :Configurator
43
+ autoload :OptionsSet
44
+ autoload :HashWithRenderStrategy
45
+ autoload :HashWithCaller
46
+ end
43
47
 
44
- autoload :Version
48
+ autoload_under 'helpers' do
49
+ autoload :HamlCapture
50
+ end
45
51
 
46
52
  include Configurator
47
53
  end
54
+
55
+ require 'blocks/engine'
@@ -1,12 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Blocks
2
4
  class BlockDefinition < OptionsSet
3
- attr_accessor :options_set,
4
- :skip_content,
5
- :skip_completely,
6
- :anonymous,
7
- *HookDefinition::HOOKS.map {|hook| "#{hook}_hooks" }
8
-
5
+ attr_accessor :skip_content,
6
+ :skip_completely,
7
+ :anonymous,
8
+ :hooks
9
9
 
10
+ def initialize(*)
11
+ self.hooks = Hash.new {|hash, key| hash[key] = [] }
12
+ super
13
+ end
14
+
10
15
  def skip(completely=false)
11
16
  self.skip_content = true
12
17
  self.skip_completely = completely
@@ -20,49 +25,46 @@ module Blocks
20
25
  !!skip_completely
21
26
  end
22
27
 
23
- def hooks_for(hook_name)
24
- self.send("#{hook_name}_hooks")
28
+ def hooks_for(hook_type, initialize_when_missing: false)
29
+ hooks[hook_type] if initialize_when_missing || hooks.key?(hook_type)
25
30
  end
26
31
 
27
- HookDefinition::HOOKS.each do |hook|
28
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
29
- def #{hook}_hooks
30
- @#{hook}_hooks ||= []
31
- end
32
- RUBY
32
+ def hooks_present?
33
+ hooks.present?
34
+ end
33
35
 
34
- define_method(hook) do |*args, &block|
35
- HookDefinition.new(self, hook, *args, &block).tap do |definition|
36
- hooks_for(hook) << definition
36
+ HookDefinition::HOOKS.each do |hook|
37
+ define_method(hook) do |*args, &hook_definition|
38
+ HookDefinition.new(self, hook, *args, &hook_definition).tap do |definition|
39
+ hooks_for(hook, initialize_when_missing: true) << definition
37
40
  end
38
41
  end
39
42
  end
40
43
 
41
- def to_s
42
- description = []
43
- description << super
44
- options = [
45
- runtime_options,
46
- standard_options,
47
- default_options
48
- ].detect(&:render_strategy)
49
-
50
- strategy = options.try(:render_strategy)
51
- render_strategy_name = if strategy == HashWithRenderStrategy::RENDER_WITH_PROXY
52
- caller_id = options.callers[HashWithRenderStrategy::RENDER_WITH_PROXY]
53
- "proxy block \"#{options[strategy]}\""
54
- elsif strategy == HashWithRenderStrategy::RENDER_WITH_BLOCK
55
- caller_id = options.callers[HashWithRenderStrategy::RENDER_WITH_BLOCK]
56
- "block defined at #{options[strategy].source_location}"
57
- elsif strategy == HashWithRenderStrategy::RENDER_WITH_PARTIAL
58
- caller_id = options.callers[HashWithRenderStrategy::RENDER_WITH_PARTIAL]
59
- "partial \"#{options[strategy]}\""
60
- end
61
- if render_strategy_name
62
- description << "Renders with #{render_strategy_name} [#{caller_id}]"
63
- end
64
-
65
- description.join("\n")
66
- end
44
+ # def to_s
45
+ # description = []
46
+ # description << super
47
+ # options = [
48
+ # standard_options,
49
+ # default_options
50
+ # ].detect(&:render_strategy)
51
+ #
52
+ # strategy = options.try(:render_strategy)
53
+ # render_strategy_name = if strategy == HashWithRenderStrategy::RENDER_WITH_PROXY
54
+ # # caller_id = options.callers[HashWithRenderStrategy::RENDER_WITH_PROXY]
55
+ # "proxy block \"#{options[strategy]}\""
56
+ # elsif strategy == HashWithRenderStrategy::RENDER_WITH_BLOCK
57
+ # # caller_id = options.callers[HashWithRenderStrategy::RENDER_WITH_BLOCK]
58
+ # "block defined at #{options[strategy].source_location}"
59
+ # elsif strategy == HashWithRenderStrategy::RENDER_WITH_PARTIAL
60
+ # # caller_id = options.callers[HashWithRenderStrategy::RENDER_WITH_PARTIAL]
61
+ # "partial \"#{options[strategy]}\""
62
+ # end
63
+ # if render_strategy_name
64
+ # # description << "Renders with #{render_strategy_name} [#{caller_id}]"
65
+ # end
66
+ #
67
+ # description.join("\n")
68
+ # end
67
69
  end
68
70
  end
@@ -1,8 +1,10 @@
1
- require 'call_with_params'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Blocks
4
4
  class Builder
5
- include CallWithParams
5
+ if defined?(Haml)
6
+ prepend HamlCapture
7
+ end
6
8
 
7
9
  # A pointer to the view context
8
10
  attr_accessor :view
@@ -11,58 +13,55 @@ module Blocks
11
13
  attr_accessor :block_definitions
12
14
 
13
15
  # Options provided during initialization of builder
14
- attr_accessor :options_set
16
+ attr_accessor :options
15
17
 
16
18
  attr_accessor :anonymous_block_number
17
19
 
18
- delegate :content_tag, to: :view
19
-
20
- delegate :render,
21
- :render_with_overrides,
22
- :deferred_render,
23
- to: :renderer
24
-
25
- delegate :runtime_options,
26
- :standard_options,
27
- :default_options,
28
- to: :options_set
20
+ delegate :with_output_buffer, :output_buffer, to: :view
29
21
 
30
- CONTENT_TAG_WRAPPER_BLOCK = :content_tag_wrapper
31
-
32
- def initialize(view, options={})
33
- if defined?(::Haml) && !view.instance_variables.include?(:@haml_buffer)
34
- class << view
35
- include Haml::Helpers
36
- end
37
- view.init_haml_helpers
38
- end
22
+ def initialize(view, options=nil)
39
23
  self.view = view
40
24
  self.block_definitions = HashWithIndifferentAccess.new do |hash, key|
41
25
  hash[key] = BlockDefinition.new(key); hash[key]
42
26
  end
43
27
  self.anonymous_block_number = 0
44
- self.options_set = OptionsSet.new("Builder Options", options)
45
- define_helper_blocks
28
+ self.options = options
29
+ end
30
+
31
+ def render(*args, &block)
32
+ renderer_class.render(self, *args, &block)
33
+ end
34
+
35
+ def render_with_overrides(*args, &block)
36
+ warn "[DEPRECATION] `render_with_overrides` is deprecated. Please use `render` instead."
37
+ render(*args, &block)
46
38
  end
47
39
 
48
- def renderer
49
- @renderer ||= Blocks.renderer_class.new(self)
40
+ def deferred_render(*args, &block)
41
+ renderer_class.deferred_render(self, *args, &block)
50
42
  end
51
43
 
52
44
  def block_for(block_name)
53
45
  block_definitions[block_name] if block_defined?(block_name)
54
46
  end
55
47
 
56
- def block_defined?(block_name)
57
- block_definitions.key?(block_name)
48
+ def hooks_for(block_name, hook_name)
49
+ block_for(block_name).try(:hooks_for, hook_name) || []
58
50
  end
59
51
 
60
- def define_each(collection, block_name_proc, *args, &block)
61
- collection.map do |object|
62
- define(call_with_params(block_name_proc, object, *args), object, *args, &block)
52
+ def capture(*args, &block)
53
+ if block.arity >= 0
54
+ args = args[0, block.arity]
55
+ end
56
+ with_output_buffer do
57
+ output_buffer << view.capture(*args, &block)
63
58
  end
64
59
  end
65
60
 
61
+ def block_defined?(block_name)
62
+ block_definitions.key?(block_name)
63
+ end
64
+
66
65
  # Define a block, unless a block by the same name is already defined.
67
66
  # <%= blocks.define :some_block_name, :parameter1 => "1", :parameter2 => "2" do |options| %>
68
67
  # <%= options[:parameter1] %> and <%= options[:parameter2] %>
@@ -79,16 +78,17 @@ module Blocks
79
78
  def define(*args, &block)
80
79
  options = args.extract_options!
81
80
 
82
- name, anonymous = if args.first
83
- [args.shift, false]
81
+ name = if args.first
82
+ args.shift
84
83
  else
84
+ anonymous = true
85
85
  self.anonymous_block_number += 1
86
- ["anonymous_block_#{anonymous_block_number}", true]
86
+ "anonymous_block_#{anonymous_block_number}"
87
87
  end
88
88
 
89
89
  block_definitions[name].tap do |block_definition|
90
- block_definition.add_options options, &block
91
- block_definition.anonymous = anonymous
90
+ block_definition.reverse_merge! options, &block
91
+ block_definition.anonymous = !!anonymous
92
92
  end
93
93
  end
94
94
 
@@ -132,8 +132,7 @@ module Blocks
132
132
  options = call_each_hash_value_with_params(options, *args) || {}
133
133
  options2 = call_each_hash_value_with_params(options2, *args) || {}
134
134
 
135
-
136
- options.symbolize_keys.merge(options2.symbolize_keys) do |key, v1, v2|
135
+ options.merge(options2) do |key, v1, v2|
137
136
  if v1.is_a?(String) && v2.is_a?(String)
138
137
  "#{v1} #{v2}"
139
138
  else
@@ -142,29 +141,66 @@ module Blocks
142
141
  end
143
142
  end
144
143
 
145
- protected
144
+ # Blocks::Builder#content_tag extends ActionView's content_tag method
145
+ # by allowing itself to be used as a wrapper, hook, or called directly,
146
+ # while also not requiring the content tag name (defaults to :div).
147
+ def content_tag(*args, &block)
148
+ options = args.extract_options!
149
+ escape = options.key?(:escape) ? options.delete(:escape) : true
150
+ if wrapper_type = options.delete(:wrapper_type)
151
+
152
+ html_option = options["#{wrapper_type}_html_option".to_sym] || options[:html_option]
153
+ wrapper_html = if html_option.is_a?(Array)
154
+ html_option.map { |html_attribute| options[html_attribute] }.compact.first
155
+ elsif html_option.present?
156
+ options[html_option]
157
+ end
146
158
 
147
- # TODO: move this logic elsewhere
148
- def define_helper_blocks
149
- define CONTENT_TAG_WRAPPER_BLOCK, defaults: { wrapper_tag: :div } do |content_block, *args|
150
- options = args.extract_options!
151
- wrapper_options = if options[:wrapper_html_option]
152
- if options[:wrapper_html_option].is_a?(Array)
153
- wrapper_attribute = nil
154
- options[:wrapper_html_option].each do |attribute|
155
- if options[attribute].present?
156
- wrapper_attribute = attribute
157
- break
158
- end
159
- end
160
- options[wrapper_attribute]
161
- else
162
- options[options[:wrapper_html_option]]
163
- end
159
+ wrapper_html = concatenating_merge(options["#{wrapper_type}_html".to_sym] || options[:html], wrapper_html, *args, options)
160
+
161
+ wrapper_tag = options["#{wrapper_type}_tag".to_sym]
162
+ end
163
+ wrapper_html ||= call_each_hash_value_with_params(options[:html], options).presence || options
164
+ wrapper_tag ||= options.delete(:tag)
165
+
166
+ if !wrapper_tag
167
+ first_arg = args.first
168
+ wrapper_tag = if first_arg.is_a?(String) || first_arg.is_a?(Symbol)
169
+ args.shift
170
+ else
171
+ :div
164
172
  end
165
- content_tag options[:wrapper_tag],
166
- concatenating_merge(options[:wrapper_html], wrapper_options, *args, options),
167
- &content_block
173
+ end
174
+
175
+ content_tag_args = [wrapper_tag]
176
+ if !block_given?
177
+ content_tag_args << (wrapper_html.delete(:content) || options[:content] || args.shift)
178
+ end
179
+ content_tag_args << wrapper_html
180
+ content_tag_args << escape
181
+
182
+ view.content_tag *content_tag_args, &block
183
+ end
184
+
185
+ protected
186
+ def renderer_class
187
+ @renderer_class ||= Blocks.renderer_class
188
+ end
189
+
190
+ def call_with_params(*args)
191
+ return nil if args.empty?
192
+ v = args.shift
193
+ v.is_a?(Proc) ? v.call(*(args[0, v.arity.abs])) : v
194
+ end
195
+
196
+ def call_each_hash_value_with_params(*args)
197
+ return {} if args.empty?
198
+
199
+ options = args.shift || {}
200
+ if options.is_a?(Proc)
201
+ call_with_params(options, *args)
202
+ else
203
+ options.inject(Hash.new) { |hash, (k, v)| hash[k] = call_with_params(v, *args); hash}
168
204
  end
169
205
  end
170
206
  end