fortitude 0.9.1-java → 0.9.2-java

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +28 -22
  4. data/CHANGES.md +50 -0
  5. data/CONTRIBUTORS.md +1 -0
  6. data/doc/.gitignore +18 -0
  7. data/doc/Gemfile +21 -0
  8. data/doc/config.rb +92 -0
  9. data/doc/source/images/background.png +0 -0
  10. data/doc/source/images/middleman.png +0 -0
  11. data/doc/source/images/why/icon_button.png +0 -0
  12. data/doc/source/images/why/icon_button@2x.png +0 -0
  13. data/doc/source/images/why/modal_dialog@2x.png +0 -0
  14. data/doc/source/index.html.pcss +96 -0
  15. data/doc/source/index.html.rb +66 -0
  16. data/doc/source/javascripts/all.js +1 -0
  17. data/doc/source/javascripts/highlight.pack.js +1 -0
  18. data/doc/source/layouts/layout.rb +55 -0
  19. data/doc/source/portable/fortitude-bootstrap.rb +53 -0
  20. data/doc/source/shared/base.pcss +62 -0
  21. data/doc/source/shared/base.rb +30 -0
  22. data/doc/source/shared/common.rb +55 -0
  23. data/doc/source/shared/standard_page.rb +40 -0
  24. data/doc/source/stylesheets/_shared_prefix.scss +25 -0
  25. data/doc/source/stylesheets/all.css.scss +7 -0
  26. data/doc/source/stylesheets/basics.css.scss +20 -0
  27. data/doc/source/stylesheets/bootstrap_importer.css.scss +1 -0
  28. data/doc/source/stylesheets/highlight/arta.css +140 -0
  29. data/doc/source/stylesheets/highlight/ascetic.css +52 -0
  30. data/doc/source/stylesheets/highlight/atelier-dune.dark.css +95 -0
  31. data/doc/source/stylesheets/highlight/atelier-dune.light.css +95 -0
  32. data/doc/source/stylesheets/highlight/atelier-forest.dark.css +95 -0
  33. data/doc/source/stylesheets/highlight/atelier-forest.light.css +95 -0
  34. data/doc/source/stylesheets/highlight/atelier-heath.dark.css +95 -0
  35. data/doc/source/stylesheets/highlight/atelier-heath.light.css +95 -0
  36. data/doc/source/stylesheets/highlight/atelier-lakeside.dark.css +95 -0
  37. data/doc/source/stylesheets/highlight/atelier-lakeside.light.css +95 -0
  38. data/doc/source/stylesheets/highlight/atelier-seaside.dark.css +95 -0
  39. data/doc/source/stylesheets/highlight/atelier-seaside.light.css +95 -0
  40. data/doc/source/stylesheets/highlight/brown_paper.css +104 -0
  41. data/doc/source/stylesheets/highlight/brown_papersq.png +0 -0
  42. data/doc/source/stylesheets/highlight/codepen-embed.css +108 -0
  43. data/doc/source/stylesheets/highlight/color-brewer.css +168 -0
  44. data/doc/source/stylesheets/highlight/dark.css +104 -0
  45. data/doc/source/stylesheets/highlight/default.css +152 -0
  46. data/doc/source/stylesheets/highlight/docco.css +135 -0
  47. data/doc/source/stylesheets/highlight/far.css +111 -0
  48. data/doc/source/stylesheets/highlight/foundation.css +136 -0
  49. data/doc/source/stylesheets/highlight/github.css +124 -0
  50. data/doc/source/stylesheets/highlight/googlecode.css +147 -0
  51. data/doc/source/stylesheets/highlight/hybrid.css +170 -0
  52. data/doc/source/stylesheets/highlight/idea.css +125 -0
  53. data/doc/source/stylesheets/highlight/ir_black.css +109 -0
  54. data/doc/source/stylesheets/highlight/kimbie.dark.css +96 -0
  55. data/doc/source/stylesheets/highlight/kimbie.light.css +96 -0
  56. data/doc/source/stylesheets/highlight/magula.css +121 -0
  57. data/doc/source/stylesheets/highlight/mono-blue.css +69 -0
  58. data/doc/source/stylesheets/highlight/monokai.css +127 -0
  59. data/doc/source/stylesheets/highlight/monokai_sublime.css +154 -0
  60. data/doc/source/stylesheets/highlight/obsidian.css +153 -0
  61. data/doc/source/stylesheets/highlight/paraiso.dark.css +95 -0
  62. data/doc/source/stylesheets/highlight/paraiso.light.css +95 -0
  63. data/doc/source/stylesheets/highlight/pojoaque.css +107 -0
  64. data/doc/source/stylesheets/highlight/pojoaque.jpg +0 -0
  65. data/doc/source/stylesheets/highlight/railscasts.css +187 -0
  66. data/doc/source/stylesheets/highlight/rainbow.css +108 -0
  67. data/doc/source/stylesheets/highlight/school_book.css +112 -0
  68. data/doc/source/stylesheets/highlight/school_book.png +0 -0
  69. data/doc/source/stylesheets/highlight/solarized_dark.css +108 -0
  70. data/doc/source/stylesheets/highlight/solarized_light.css +108 -0
  71. data/doc/source/stylesheets/highlight/sunburst.css +164 -0
  72. data/doc/source/stylesheets/highlight/tomorrow-night-blue.css +95 -0
  73. data/doc/source/stylesheets/highlight/tomorrow-night-bright.css +94 -0
  74. data/doc/source/stylesheets/highlight/tomorrow-night-eighties.css +94 -0
  75. data/doc/source/stylesheets/highlight/tomorrow-night.css +95 -0
  76. data/doc/source/stylesheets/highlight/tomorrow.css +92 -0
  77. data/doc/source/stylesheets/highlight/vs.css +93 -0
  78. data/doc/source/stylesheets/highlight/xcode.css +158 -0
  79. data/doc/source/stylesheets/highlight/zenburn.css +118 -0
  80. data/doc/source/why/a_larger_view.html.rb +774 -0
  81. data/doc/source/why/a_simple_helper.html.rb +332 -0
  82. data/doc/source/why/building_a_rich_modal_dialog.html.rb +156 -0
  83. data/doc/source/why/commonality_and_inheritance.html.rb +564 -0
  84. data/doc/source/why/example_list.rb +60 -0
  85. data/doc/source/why/example_page.rb +116 -0
  86. data/doc/source/why/index.html.rb +86 -0
  87. data/doc/source/why/other_benefits.html.rb +110 -0
  88. data/fortitude.gemspec +6 -1
  89. data/lib/fortitude/doctypes/html4_tags_strict.rb +1 -0
  90. data/lib/fortitude/doctypes/html5.rb +1 -0
  91. data/lib/fortitude/method_templates/tag_method_template.rb.smpl +27 -14
  92. data/lib/fortitude/rails/helpers.rb +2 -2
  93. data/lib/fortitude/rendering_context.rb +10 -1
  94. data/lib/fortitude/tags/tag.rb +3 -2
  95. data/lib/fortitude/tags/tag_support.rb +8 -3
  96. data/lib/fortitude/tilt/fortitude_template.rb +6 -2
  97. data/lib/fortitude/version.rb +1 -1
  98. data/lib/fortitude/widget.rb +2 -0
  99. data/lib/fortitude/widget/convenience.rb +30 -0
  100. data/lib/fortitude/widget/files.rb +22 -11
  101. data/lib/fortitude/widget/needs.rb +5 -3
  102. data/spec/helpers/system_helpers.rb +1 -0
  103. data/spec/rails/development_mode_system_spec.rb +0 -1
  104. data/spec/rails/rendering_system_spec.rb +20 -1
  105. data/spec/rails/templates/rendering_system_spec/app/controllers/rendering_system_spec_controller.rb +13 -0
  106. data/spec/rails/templates/rendering_system_spec/app/views/rendering_system_spec/render_hash_subclass.rb +18 -0
  107. data/spec/rails/templates/rendering_system_spec/lib/my_hash.rb +5 -0
  108. data/spec/system/convenience_methods_system_spec.rb +166 -0
  109. data/spec/system/formatting_system_spec.rb +25 -1
  110. data/spec/system/tag_rendering_system_spec.rb +73 -0
  111. data/spec/system/tilt_system_spec.rb +31 -0
  112. data/spec/system/widget_class_from_spec.rb +20 -4
  113. metadata +91 -4
@@ -59,9 +59,9 @@ module Fortitude
59
59
  # form_helper
60
60
  FORM_FOR_YIELDED_METHODS_TO_OUTPUT =
61
61
  # Directly from form_helper
62
- %w{check_box color_field date_field datetime_field datetime_local_field} +
62
+ %w{button check_box color_field date_field datetime_field datetime_local_field} +
63
63
  %w{email_field file_field hidden_field label month_field number_field password_field phone_field} +
64
- %w{radio_button range_field search_field telephone_field text_area text_field time_field url_field} +
64
+ %w{radio_button range_field search_field submit telephone_field text_area text_field time_field url_field} +
65
65
  %w{week_field} +
66
66
 
67
67
  # From form_options_helper
@@ -140,6 +140,15 @@ module Fortitude
140
140
  @newline_needed = true
141
141
  end
142
142
 
143
+ def suppress_formatting!
144
+ @suppress_formatting_level ||= 0
145
+ @suppress_formatting_level += 1
146
+ end
147
+
148
+ def desuppress_formatting!
149
+ @suppress_formatting_level -= 1
150
+ end
151
+
143
152
  def current_indent
144
153
  (" " * @indent).freeze
145
154
  end
@@ -155,7 +164,7 @@ module Fortitude
155
164
  end
156
165
 
157
166
  def about_to_output_non_whitespace!
158
- if @newline_needed
167
+ if @newline_needed && ((@suppress_formatting_level ||= 0) == 0)
159
168
  if @have_output
160
169
  o = @output_buffer_holder.output_buffer
161
170
  o.original_concat(NEWLINE)
@@ -31,7 +31,7 @@ module Fortitude
31
31
 
32
32
  def initialize(name, options = { })
33
33
  options.assert_valid_keys(:valid_attributes, :newline_before, :content_allowed, :can_enclose,
34
- :allow_data_attributes, :allow_aria_attributes, :spec, :escape_direct_content)
34
+ :allow_data_attributes, :allow_aria_attributes, :spec, :escape_direct_content, :suppress_formatting_inside)
35
35
 
36
36
  @name = self.class.normalize_tag_name(name)
37
37
 
@@ -42,6 +42,7 @@ module Fortitude
42
42
  @allow_data_attributes = true unless options.has_key?(:allow_data_attributes) && (! options[:allow_data_attributes])
43
43
  @allow_aria_attributes = true unless options.has_key?(:allow_aria_attributes) && (! options[:allow_aria_attributes])
44
44
  @escape_direct_content = true unless options.has_key?(:escape_direct_content) && (! options[:escape_direct_content])
45
+ @suppress_formatting_inside = !! options[:suppress_formatting_inside]
45
46
  @spec = options[:spec]
46
47
  end
47
48
 
@@ -141,7 +142,7 @@ module Fortitude
141
142
  needs_formatting = !! options[:enable_formatting]
142
143
 
143
144
  if needs_formatting && @newline_before
144
- yield_call = "_fortitude_formatted_output_tag_yield(:#{name}) { yield }"
145
+ yield_call = "_fortitude_formatted_output_tag_yield(:#{name}, #{@suppress_formatting_inside.inspect}) { yield }"
145
146
  elsif needs_formatting
146
147
  yield_call = "yield; rc.about_to_output_non_whitespace!"
147
148
  else
@@ -18,17 +18,22 @@ module Fortitude
18
18
 
19
19
  FORTITUDE_TAG_PARTIAL_OPEN_END = ">".freeze
20
20
 
21
- def _fortitude_formatted_output_tag_yield(tag_name)
21
+ def _fortitude_formatted_output_tag_yield(tag_name, suppress_formatting_inside)
22
22
  rc = @_fortitude_rendering_context
23
23
  if rc.format_output?
24
24
  rc.needs_newline!
25
25
  rc.increase_indent!
26
26
  begin
27
+ rc.suppress_formatting! if suppress_formatting_inside
27
28
  yield
28
29
  ensure
29
30
  rc.decrease_indent!
30
- rc.needs_newline!
31
- rc.about_to_output_non_whitespace!
31
+ if suppress_formatting_inside
32
+ rc.desuppress_formatting!
33
+ else
34
+ rc.needs_newline!
35
+ rc.about_to_output_non_whitespace!
36
+ end
32
37
  end
33
38
  else
34
39
  yield
@@ -7,7 +7,11 @@ module Fortitude
7
7
  module Tilt
8
8
  class FortitudeTemplate < ::Tilt::Template
9
9
  def prepare
10
- ::Object.class_eval(data)
10
+ if file && line
11
+ ::Object.class_eval(data, file, line)
12
+ else
13
+ ::Object.class_eval(data)
14
+ end
11
15
 
12
16
  # 2014-06-19 ageweke -- Earlier versions of Tilt try to instantiate the engine with an empty tempate as a way
13
17
  # of making sure it can be created, so we have to support this case.
@@ -26,7 +30,7 @@ module Fortitude
26
30
  :yield_block => block, :render_yield_result => false,
27
31
  :helpers_object => scope, :instance_variables_object => scope })
28
32
 
29
- widget_assigns = { }.with_indifferent_access
33
+ widget_assigns = { }
30
34
 
31
35
  scope.instance_variables.each do |instance_variable_name|
32
36
  if instance_variable_name.to_s =~ /^\@(.*)$/
@@ -1,3 +1,3 @@
1
1
  module Fortitude
2
- VERSION = "0.9.1"
2
+ VERSION = "0.9.2"
3
3
  end
@@ -15,6 +15,7 @@ require 'fortitude/widget/capturing'
15
15
  require 'fortitude/widget/rendering'
16
16
  require 'fortitude/widget/temporary_overrides'
17
17
  require 'fortitude/widget/files'
18
+ require 'fortitude/widget/convenience'
18
19
 
19
20
  require 'fortitude/doctypes'
20
21
 
@@ -40,6 +41,7 @@ module Fortitude
40
41
  include Fortitude::Widget::Rendering
41
42
  include Fortitude::Widget::TemporaryOverrides
42
43
  include Fortitude::Widget::Files
44
+ include Fortitude::Widget::Convenience
43
45
 
44
46
  if defined?(::Rails)
45
47
  require 'fortitude/rails/widget_methods'
@@ -0,0 +1,30 @@
1
+ require 'active_support/concern'
2
+
3
+ module Fortitude
4
+ class Widget
5
+ module Convenience
6
+ def content_and_attributes_from_tag_arguments(content_or_attributes = nil, attributes = nil)
7
+ if (! attributes) && content_or_attributes.kind_of?(Hash)
8
+ [ nil, (content_or_attributes || { }) ]
9
+ else
10
+ [ content_or_attributes, (attributes || { }) ]
11
+ end
12
+ end
13
+
14
+ def add_css_classes(classes_to_add, a = nil, b = nil)
15
+ classes_to_add = Array(classes_to_add)
16
+ content, attributes = content_and_attributes_from_tag_arguments(a, b)
17
+
18
+ attributes = if attributes.has_key?('class')
19
+ attributes.merge('class' => (Array(attributes['class'] || [ ]) + classes_to_add))
20
+ else
21
+ attributes.merge(:class => (Array(attributes[:class] || [ ]) + classes_to_add))
22
+ end
23
+
24
+ [ content, attributes ]
25
+ end
26
+
27
+ alias_method :add_css_class, :add_css_classes
28
+ end
29
+ end
30
+ end
@@ -7,14 +7,16 @@ module Fortitude
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  class CannotDetermineWidgetClassNameError < StandardError
10
- attr_reader :tried_class_names, :filename, :magic_comment_texts
10
+ attr_reader :tried_class_names, :filename, :magic_comment_texts, :resulting_objects, :class_names_to_try
11
11
 
12
12
  def initialize(tried_class_names, options = { })
13
- options.assert_valid_keys(:filename, :magic_comment_texts)
13
+ options.assert_valid_keys(:filename, :magic_comment_texts, :resulting_objects, :class_names_to_try)
14
14
 
15
15
  @tried_class_names = tried_class_names
16
16
  @filename = options[:filename]
17
17
  @magic_comment_texts = options[:magic_comment_texts]
18
+ @resulting_objects = options[:resulting_objects]
19
+ @class_names_to_try = options[:class_names_to_try]
18
20
  from_what = filename ? "from the file '#{filename}'" : "from some Fortitude source code"
19
21
 
20
22
  super %{You asked for a Fortitude widget class #{from_what},
@@ -25,9 +27,10 @@ We tried the following class names, in order:
25
27
  #{tried_class_names.join("\n")}
26
28
 
27
29
  ...but none of them both existed and were a class that eventually inherits from
28
- ::Fortitude::Widget.
30
+ ::Fortitude::Widget. (We got back resulting objects: #{resulting_objects.inspect})
29
31
 
30
- You can either pass the class name into this method via the :class_names_to_try option,
32
+ You can either pass the class name into this method via the :class_names_to_try option
33
+ (we were passed #{class_names_to_try.inspect}),
31
34
  or add a "magic comment" to the source code of this widget that looks like this:
32
35
 
33
36
  #!<token>: <class_name>
@@ -70,8 +73,9 @@ or add a "magic comment" to the source code of this widget that looks like this:
70
73
  scan_source_for_possible_class_names(source)
71
74
 
72
75
  out = widget_class_from_class_names(all_class_names)
76
+ resulting_objects = out[:resulting_objects]
73
77
 
74
- unless out
78
+ unless out[:widget_class]
75
79
  if options[:filename]
76
80
  require options[:filename]
77
81
  else
@@ -79,11 +83,13 @@ or add a "magic comment" to the source code of this widget that looks like this:
79
83
  end
80
84
 
81
85
  out = widget_class_from_class_names(all_class_names)
86
+ resulting_objects += out[:resulting_objects]
82
87
  end
83
88
 
84
- out || (
89
+ out[:widget_class] || (
85
90
  raise CannotDetermineWidgetClassNameError.new(all_class_names, :magic_comment_texts => magic_comment_texts,
86
- :filename => options[:filename]))
91
+ :filename => options[:filename], :resulting_objects => resulting_objects,
92
+ :class_names_to_try => options[:class_names_to_try]))
87
93
  end
88
94
 
89
95
  private
@@ -118,8 +124,9 @@ or add a "magic comment" to the source code of this widget that looks like this:
118
124
  while module_nesting.length > 0
119
125
  possible_module_name = module_nesting.join("::")
120
126
  out.reverse.each do |class_name|
121
- out.unshift("#{possible_module_name}::#{class_name}")
127
+ out.push("#{possible_module_name}::#{class_name}")
122
128
  end
129
+ out.push(possible_module_name)
123
130
  module_nesting.pop
124
131
  end
125
132
 
@@ -127,7 +134,10 @@ or add a "magic comment" to the source code of this widget that looks like this:
127
134
  end
128
135
 
129
136
  def widget_class_from_class_names(class_names)
130
- out = nil
137
+ out = {
138
+ :widget_class => nil,
139
+ :resulting_objects => [ ]
140
+ }
131
141
 
132
142
  class_names.each do |class_name|
133
143
  class_name = $1 if class_name =~ /^:+(.*)$/i
@@ -138,11 +148,12 @@ or add a "magic comment" to the source code of this widget that looks like this:
138
148
  end
139
149
 
140
150
  if is_widget_class?(klass)
141
- out = klass
151
+ out[:widget_class] = klass
142
152
  break
153
+ elsif klass
154
+ out[:resulting_objects] << klass
143
155
  end
144
156
  end
145
-
146
157
  out
147
158
  end
148
159
 
@@ -80,11 +80,13 @@ module Fortitude
80
80
 
81
81
  # PUBLIC API
82
82
  def extract_needed_assigns_from(input)
83
- input = input.with_indifferent_access
84
-
85
83
  out = { }
86
84
  needs_as_hash.keys.each do |name|
87
- out[name] = input[name] if input.has_key?(name)
85
+ if input.has_key?(name)
86
+ out[name] = input[name]
87
+ elsif input.has_key?(name.to_s)
88
+ out[name] = input[name.to_s]
89
+ end
88
90
  end
89
91
  out
90
92
  end
@@ -66,6 +66,7 @@ module SystemHelpers
66
66
  tag :script, :newline_before => true, :escape_direct_content => false
67
67
  tag :head, :newline_before => true
68
68
  tag :style, :newline_before => true, :escape_direct_content => false
69
+ tag :pre, :newline_before => true, :suppress_formatting_inside => true
69
70
  end
70
71
 
71
72
  class TestWidgetClass < Fortitude::Widget
@@ -97,7 +97,6 @@ describe "Rails development-mode support", :type => :rails do
97
97
  end
98
98
 
99
99
  sleep 1
100
- $stderr.puts "checking for #{current_form.inspect}"
101
100
  expect_match("edit", /#{Regexp.escape(current_form.to_s)}/i)
102
101
 
103
102
  current_form = if current_form == :full_reference
@@ -52,10 +52,16 @@ describe "Rails rendering support", :type => :rails do
52
52
  expect(response.header['Content-Type']).to match(%r{text/html}i)
53
53
  end
54
54
 
55
- it "should let you render a widget with 'render \"foo\"'" do
55
+ it "should let you render a widget with 'render \"foo\" and the full path'" do
56
+ skip "Rails 4.2 makes this mean something different (render :template, vs. render :file)" unless rails_server.rails_version =~ /^(3\.|4\.[01]\.)/
56
57
  expect_match("render_widget_via_file_path", /hello from a widget named Fred/)
57
58
  end
58
59
 
60
+ it "should let you render a widget with 'render \"foo\"' and the template path" do
61
+ skip "Rails 4.2 enables this" if rails_server.rails_version =~ /^(3\.|4\.[01]\.)/
62
+ expect_match("render_widget_via_template_path", /hello, world/)
63
+ end
64
+
59
65
  it "should let you render a widget with 'render :file =>'" do
60
66
  expect_match("render_widget_via_colon_file", /hello from a widget named Fred/)
61
67
  end
@@ -67,6 +73,19 @@ describe "Rails rendering support", :type => :rails do
67
73
  it "should let you render a widget inline, and use all instance and local variables, with locals overriding instance variables" do
68
74
  expect_match("render_widget_via_inline_with_var_access", /this is an inline widget named Fred, and it is 27 years old, and friends with Mary/)
69
75
  end
76
+
77
+ it "should let you pass a subclass of Hash, and not accidentally get rid of it via #with_indifferent_access" do
78
+ expect_match("render_hash_subclass", /the_hash class: MyHash/,
79
+ /the_hash\[:foo\] &quot;bar&quot;/,
80
+ /the_hash\[&quot;foo&quot;\] nil/,
81
+ /the_hash\[:bar\] nil/,
82
+ /the_hash\[&quot;bar&quot;\] :baz/,
83
+ /other_hash class: Hash/,
84
+ /other_hash\[:quux\] nil/,
85
+ /other_hash\[&quot;quux&quot;\] &quot;bazzle&quot;/,
86
+ /other_hash\[:marph\] :bar/,
87
+ /other_hash\[&quot;marph&quot;\] nil/)
88
+ end
70
89
  end
71
90
 
72
91
  describe "rendering in a widget" do
@@ -37,6 +37,10 @@ class RenderingSystemSpecController < ApplicationController
37
37
  render File.join(Rails.root, 'app', 'views', 'widget_to_render')
38
38
  end
39
39
 
40
+ def render_widget_via_template_path
41
+ render "rendering_system_spec/trivial_widget"
42
+ end
43
+
40
44
  def render_widget_via_colon_file
41
45
  @name = "Fred"
42
46
  render :file => File.join(Rails.root, 'app', 'views', 'widget_to_render')
@@ -125,4 +129,13 @@ class RenderingSystemSpecController < ApplicationController
125
129
  @d = "quux<marph"
126
130
  @e = "marph>foo".html_safe
127
131
  end
132
+
133
+ def render_hash_subclass
134
+ require 'my_hash'
135
+
136
+ @the_hash = MyHash.new
137
+ @the_hash[:foo] = 'bar'
138
+ @the_hash['bar'] = :baz
139
+ @other_hash = { 'quux' => 'bazzle', :marph => :bar }
140
+ end
128
141
  end
@@ -0,0 +1,18 @@
1
+ class Views::RenderingSystemSpec::RenderHashSubclass < Fortitude::Widgets::Html5
2
+ needs :the_hash, :other_hash
3
+
4
+ def content
5
+ text "the_hash class: #{the_hash.class.name}\n"
6
+ # text "is_my_hash? #{the_hash.is_my_hash?.inspect}\n"
7
+ text "the_hash[:foo] #{the_hash[:foo].inspect}\n"
8
+ text "the_hash[\"foo\"] #{the_hash['foo'].inspect}\n"
9
+ text "the_hash[:bar] #{the_hash[:bar].inspect}\n"
10
+ text "the_hash[\"bar\"] #{the_hash['bar'].inspect}\n"
11
+
12
+ text "other_hash class: #{other_hash.class.name}\n"
13
+ text "other_hash[:quux] #{other_hash[:quux].inspect}\n"
14
+ text "other_hash[\"quux\"] #{other_hash['quux'].inspect}\n"
15
+ text "other_hash[:marph] #{other_hash[:marph].inspect}\n"
16
+ text "other_hash[\"marph\"] #{other_hash['marph'].inspect}\n"
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ class MyHash < Hash
2
+ def is_my_hash?
3
+ :my_hash
4
+ end
5
+ end
@@ -49,4 +49,170 @@ hi, there
49
49
  </div>})
50
50
  end
51
51
  end
52
+
53
+ describe "#content_and_attributes_from_tag_arguments" do
54
+ let(:test_widget_instance) { widget_class.new }
55
+
56
+ def caafta(*args)
57
+ test_widget_instance.content_and_attributes_from_tag_arguments(*args)
58
+ end
59
+
60
+ it "should return nil and empty-hash for passing nothing" do
61
+ expect(caafta()).to eq([ nil, { } ])
62
+ end
63
+
64
+ it "should return text if passed just text" do
65
+ expect(caafta("foo")).to eq([ "foo", { } ])
66
+ end
67
+
68
+ it "should return attributes if passed just that" do
69
+ expect(caafta(:class => :bar)).to eq([ nil, { :class => :bar }])
70
+ end
71
+
72
+ it "should return text and attributes if passed that" do
73
+ expect(caafta("foo", :class => :bar)).to eq([ "foo", { :class => :bar }])
74
+ end
75
+ end
76
+
77
+ describe "#add_css_classes" do
78
+ let(:widget_class_with_p_added_base) {
79
+ widget_class do
80
+ def classes_to_add
81
+ [ :foo, :bar ]
82
+ end
83
+
84
+ def call_add_css_classes(*args)
85
+ add_css_classes(classes_to_add, *args)
86
+ end
87
+
88
+ def p_added(*args, &block)
89
+ p(*call_add_css_classes(*args), &block)
90
+ end
91
+ end
92
+ }
93
+
94
+ def widget_class_with_p_added(&block)
95
+ widget_class(:superclass => widget_class_with_p_added_base, &block)
96
+ end
97
+
98
+ def widget_class_with_p_added_content(&block)
99
+ widget_class_with_content(:superclass => widget_class_with_p_added_base, &block)
100
+ end
101
+
102
+ it "should correctly add classes if passed nothing at all" do
103
+ expect(render(widget_class_with_p_added_content { p_added })).to eq(%{<p class="foo bar"></p>})
104
+ end
105
+
106
+ it "should correctly add classes if passed just text" do
107
+ expect(render(widget_class_with_p_added_content { p_added "hello" })).to eq(%{<p class="foo bar">hello</p>})
108
+ end
109
+
110
+ it "should correctly add classes if passed just other attributes" do
111
+ output = render(widget_class_with_p_added_content { p_added :id => :whatever })
112
+ expect(output).to match(%r{<p [^>]*></p>})
113
+ expect(output).to match(%r{id="whatever"})
114
+ expect(output).to match(%r{class="foo bar"})
115
+ end
116
+
117
+ it "should correctly add classes if passed text, then attributes" do
118
+ output = render(widget_class_with_p_added_content { p_added "hello", :id => :whatever })
119
+ expect(output).to match(%r{<p [^>]*>hello</p>})
120
+ expect(output).to match(%r{id="whatever"})
121
+ expect(output).to match(%r{class="foo bar"})
122
+ end
123
+
124
+ it "should correctly add classes if passed nil, then attributes" do
125
+ output = render(widget_class_with_p_added_content { p_added nil, :id => :whatever })
126
+ expect(output).to match(%r{<p [^>]*></p>})
127
+ expect(output).to match(%r{id="whatever"})
128
+ expect(output).to match(%r{class="foo bar"})
129
+ end
130
+
131
+ it "should correctly add classes if passed text, then explicitly-nil attributes" do
132
+ output = render(widget_class_with_p_added_content { p_added "hello", nil })
133
+ expect(output).to match(%r{<p class="foo bar">hello</p>})
134
+ end
135
+
136
+ it "should correctly add classes if passed nil and nil" do
137
+ expect(render(widget_class_with_p_added_content { p_added nil, nil })).to eq(%{<p class="foo bar"></p>})
138
+ end
139
+
140
+ it "should correctly add just a single class" do
141
+ wc = widget_class_with_p_added do
142
+ def classes_to_add
143
+ :foo
144
+ end
145
+
146
+ def content
147
+ p_added "hello"
148
+ end
149
+ end
150
+ expect(render(wc)).to eq(%{<p class="foo">hello</p>})
151
+ end
152
+
153
+ def render_and_extract_classes(class_or_widget)
154
+ output = render(class_or_widget)
155
+
156
+ if output =~ %r{^<p class="(.*)"></p>}
157
+ $1.split(" ")
158
+ else
159
+ raise "Unexpected content: #{output.inspect}"
160
+ end
161
+ end
162
+
163
+ def expect_classes_transform(original_hash, expected_classes)
164
+ expect(render_and_extract_classes(widget_class_with_p_added_content { p_added(original_hash) }).sort).to eq(
165
+ expected_classes.sort)
166
+ end
167
+
168
+ it "should correctly add classes if the base has classes specified with a symbol" do
169
+ expect_classes_transform({ :class => 'orig' }, %w{orig foo bar})
170
+ end
171
+
172
+ it "should correctly add classes if the base has classes specified with a string" do
173
+ expect_classes_transform({ 'class' => 'orig' }, %w{orig foo bar})
174
+ end
175
+
176
+ it "should correctly add classes if the base has multiple classes" do
177
+ expect_classes_transform({ :class => [ 'orig1', 'orig2', 'orig3' ] }, %w{orig1 orig2 orig3 foo bar})
178
+ end
179
+
180
+ it "should correctly add classes if the base has just one class" do
181
+ expect_classes_transform({ :class => 'orig' }, %w{orig foo bar})
182
+ end
183
+
184
+ it "should correctly add classes if the base has explicit nil for :class" do
185
+ expect_classes_transform({ 'class' => nil }, %w{foo bar})
186
+ end
187
+
188
+ it "should correctly add classes if the base has explicit empty-string for :class" do
189
+ expect_classes_transform({ 'class' => '' }, %w{foo bar})
190
+ end
191
+
192
+ it "should correctly add classes if the base has explicit false for :class" do
193
+ expect_classes_transform({ :class => false }, %w{foo bar})
194
+ end
195
+
196
+ it "should correctly add classes if the base has an array for :class" do
197
+ expect_classes_transform({ :class => [ 'orig1', 'orig2', 'orig3' ] }, %w{orig1 orig2 orig3 foo bar})
198
+ end
199
+
200
+ it "should correctly add classes if the base has a whitespace-separated array of classes for :class" do
201
+ expect_classes_transform({ 'class' => 'orig1 orig2 orig3' }, %w{foo bar orig1 orig2 orig3})
202
+ end
203
+
204
+ it "should allow being called as #add_css_class" do
205
+ add_css_class_class = widget_class do
206
+ def p_added(*args, &block)
207
+ p(*add_css_class('foo', *args), &block)
208
+ end
209
+
210
+ def content
211
+ p_added "hello"
212
+ end
213
+ end
214
+
215
+ expect(render(add_css_class_class)).to eq('<p class="foo">hello</p>')
216
+ end
217
+ end
52
218
  end