Skip to content

Commit

Permalink
Make assert_select_rjs code more readable, make use of unused constan…
Browse files Browse the repository at this point in the history
…ts and use more simple Regexps.

[#540 state:resolved]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
  • Loading branch information
miloops authored and jeremy committed Aug 30, 2008
1 parent 6450d6c commit 11eb29f
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 52 deletions.
78 changes: 26 additions & 52 deletions actionpack/lib/action_controller/assertions/selector_assertions.rb
Expand Up @@ -396,54 +396,31 @@ def count_description(min, max) #:nodoc:
# # The same, but shorter.
# assert_select "ol>li", 4
def assert_select_rjs(*args, &block)
rjs_type = nil
arg = args.shift
rjs_type = args.first.is_a?(Symbol) ? args.shift : nil
id = args.first.is_a?(String) ? args.shift : nil

# If the first argument is a symbol, it's the type of RJS statement we're looking
# for (update, replace, insertion, etc). Otherwise, we're looking for just about
# any RJS statement.
if arg.is_a?(Symbol)
rjs_type = arg

if rjs_type
if rjs_type == :insert
arg = args.shift
position = arg
insertion = "insert_#{arg}".to_sym
raise ArgumentError, "Unknown RJS insertion type #{arg}" unless RJS_STATEMENTS[insertion]
position = args.shift
insertion = "insert_#{position}".to_sym
raise ArgumentError, "Unknown RJS insertion type #{position}" unless RJS_STATEMENTS[insertion]
statement = "(#{RJS_STATEMENTS[insertion]})"
else
raise ArgumentError, "Unknown RJS statement type #{rjs_type}" unless RJS_STATEMENTS[rjs_type]
statement = "(#{RJS_STATEMENTS[rjs_type]})"
end
arg = args.shift
else
statement = "#{RJS_STATEMENTS[:any]}"
end
position ||= Regexp.new(RJS_INSERTIONS.join('|'))

# Next argument we're looking for is the element identifier. If missing, we pick
# any element.
if arg.is_a?(String)
id = Regexp.quote(arg)
arg = args.shift
else
id = "[^\"]*"
end

pattern =
case rjs_type
when :chained_replace, :chained_replace_html
Regexp.new("\\$\\(\"#{id}\"\\)#{statement}\\(#{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
when :remove, :show, :hide, :toggle
Regexp.new("#{statement}\\(\"#{id}\"\\)")
when :replace, :replace_html
Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)")
when :insert, :insert_html
Regexp.new("Element.insert\\(\\\"#{id}\\\", \\{ #{position}: #{RJS_PATTERN_HTML} \\}\\);")
else
Regexp.union(Regexp.new("#{statement}\\(\"#{id}\", #{RJS_PATTERN_HTML}\\)"),
Regexp.new("Element.insert\\(\\\"#{id}\\\", \\{ #{position}: #{RJS_PATTERN_HTML} \\}\\);"))
end
# any element, otherwise we replace it in the statement.
pattern = Regexp.new(
id ? statement.gsub(RJS_ANY_ID, "\"#{id}\"") : statement
)

# Duplicate the body since the next step involves destroying it.
matches = nil
Expand Down Expand Up @@ -588,26 +565,23 @@ def assert_select_email(&block)

protected
unless const_defined?(:RJS_STATEMENTS)
RJS_STATEMENTS = {
:replace => /Element\.replace/,
:replace_html => /Element\.update/,
:chained_replace => /\.replace/,
:chained_replace_html => /\.update/,
:remove => /Element\.remove/,
:show => /Element\.show/,
:hide => /Element\.hide/,
:toggle => /Element\.toggle/
RJS_PATTERN_HTML = "\"((\\\\\"|[^\"])*)\""
RJS_ANY_ID = "\"([^\"])*\""
RJS_STATEMENTS = {
:chained_replace => "\\$\\(#{RJS_ANY_ID}\\)\\.replace\\(#{RJS_PATTERN_HTML}\\)",
:chained_replace_html => "\\$\\(#{RJS_ANY_ID}\\)\\.update\\(#{RJS_PATTERN_HTML}\\)",
:replace_html => "Element\\.update\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)",
:replace => "Element\\.replace\\(#{RJS_ANY_ID}, #{RJS_PATTERN_HTML}\\)"
}
RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
RJS_PATTERN_HTML = /"((\\"|[^"])*)"/
RJS_INSERTIONS = [:top, :bottom, :before, :after]
[:remove, :show, :hide, :toggle].each do |action|
RJS_STATEMENTS[action] = "Element\\.#{action}\\(#{RJS_ANY_ID}\\)"
end
RJS_INSERTIONS = ["top", "bottom", "before", "after"]
RJS_INSERTIONS.each do |insertion|
RJS_STATEMENTS["insert_#{insertion}".to_sym] = /Element.insert\(\"([^\"]*)\", \{ #{insertion.to_s.downcase}: #{RJS_PATTERN_HTML} \}\);/
RJS_STATEMENTS["insert_#{insertion}".to_sym] = "Element.insert\\(#{RJS_ANY_ID}, \\{ #{insertion}: #{RJS_PATTERN_HTML} \\}\\)"
end
RJS_STATEMENTS[:insert_html] = Regexp.new(RJS_INSERTIONS.collect do |insertion|
/Element.insert\(\"([^\"]*)\", \{ #{insertion.to_s.downcase}: #{RJS_PATTERN_HTML} \}\);/
end.join('|'))
RJS_PATTERN_EVERYTHING = Regexp.new("#{RJS_STATEMENTS[:any]}\\(\"([^\"]*)\", #{RJS_PATTERN_HTML}\\)", Regexp::MULTILINE)
RJS_STATEMENTS[:insert_html] = "Element.insert\\(#{RJS_ANY_ID}, \\{ (#{RJS_INSERTIONS.join('|')}): #{RJS_PATTERN_HTML} \\}\\)"
RJS_STATEMENTS[:any] = Regexp.new("(#{RJS_STATEMENTS.values.join('|')})")
RJS_PATTERN_UNICODE_ESCAPED_CHAR = /\\u([0-9a-zA-Z]{4})/
end

Expand All @@ -621,8 +595,8 @@ def response_from_page_or_rjs()
root = HTML::Node.new(nil)

while true
next if body.sub!(RJS_PATTERN_EVERYTHING) do |match|
html = unescape_rjs($3)
next if body.sub!(RJS_STATEMENTS[:any]) do |match|
html = unescape_rjs(match)
matches = HTML::Document.new(html).root.children.select { |n| n.tag? }
root.children.concat matches
""
Expand Down
5 changes: 5 additions & 0 deletions actionpack/test/controller/assert_select_test.rb
Expand Up @@ -599,6 +599,11 @@ def test_assert_select_rjs_for_positioned_insert
end
end

def test_assert_select_rjs_raise_errors
assert_raises(ArgumentError) { assert_select_rjs(:destroy) }
assert_raises(ArgumentError) { assert_select_rjs(:insert, :left) }
end

# Simple selection from a single result.
def test_nested_assert_select_rjs_with_single_result
render_rjs do |page|
Expand Down

3 comments on commit 11eb29f

@dchelimsky
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following test fails as of this commit:

  def test_assert_select_rjs_for_positioned_insert_should_fail_when_mixing_arguments
    render_rjs do |page|
      page.insert_html :top, "test1", "<div id=\"1\">foo</div>"
      page.insert_html :bottom, "test2", "<div id=\"2\">foo</div>"
    end
    assert_raises {assert_select_rjs :insert, :top, "test2"}
  end

See http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/982 for more info.

@greatseth
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, if we’re talking about making code more readable, I don’t understand why people ever have ternary expressions that can return nil.

args.shift if args.first.is_a?(Symbol)

seems better for readability than

args.first.is_a?(Symbol) ? args.shift : nil

@greatseth
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

granted, you’d have to do it like

foo = (bar if baz)

for the example here, which is maybe a little weird. I think I was thinking of situations where I did this behavior when assigning ivars, which of course relies on their defaulting to nil anyway.

so probably nevermind my ill conceived comment.

sheepish

Please sign in to comment.