fortitude 0.9.1-java → 0.9.2-java

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