Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Generate XML in a cleaner way. Completely unexpected error.

  • Loading branch information...
commit 2a8645119d0f82b2191c9800ecf9e0653ebe43cd 1 parent eb313fe
@jyurek jyurek authored
View
4 features/rails.feature
@@ -41,11 +41,13 @@ Feature: Install the Gem in a Rails application
Then the command should have run successfully
When I configure the notifier to use the following configuration lines:
"""
- config.api_key = "myapikey"
+ raise "sharks"
+ config.api_key = "OMG WHAAAAAAT"
config.project_root = "argle/bargle"
"""
And I define a response for "TestController#index":
"""
+ logger.info(HoptoadNotifier.configuration.project_root)
session[:value] = "test"
raise RuntimeError, "some message"
"""
View
1  lib/hoptoad_notifier.rb
@@ -13,6 +13,7 @@
require 'hoptoad_notifier/backtrace'
require 'hoptoad_notifier/rack'
require 'hoptoad_notifier/user_informer'
+require 'hoptoad_notifier/xml_var_generator'
require 'hoptoad_notifier/railtie' if defined?(Rails::Railtie)
View
67 lib/hoptoad_notifier/notice.rb
@@ -103,7 +103,7 @@ def initialize(args)
also_use_rack_params_filters
find_session_data
- clean_params
+ filter_params
clean_rack_request_data
end
@@ -140,18 +140,18 @@ def to_xml
request.component(controller)
request.action(action)
unless parameters.nil? || parameters.empty?
- request.params do |params|
- xml_vars_for(params, parameters)
+ request.params do |builder|
+ XmlVarGenerator.new(parameters).build(builder)
end
end
unless session_data.nil? || session_data.empty?
- request.session do |session|
- xml_vars_for(session, session_data)
+ request.session do |builder|
+ XmlVarGenerator.new(session_data).build(builder)
end
end
unless cgi_data.nil? || cgi_data.empty?
- request.tag!("cgi-data") do |cgi_datum|
- xml_vars_for(cgi_datum, cgi_data)
+ request.tag!("cgi-data") do |builder|
+ XmlVarGenerator.new(cgi_data).build(builder)
end
end
end
@@ -224,61 +224,28 @@ def from_exception(attribute)
end
end
- # Removes non-serializable data from the given attribute.
- # See #clean_unserializable_data
- def clean_unserializable_data_from(attribute)
- self.send(:"#{attribute}=", clean_unserializable_data(send(attribute)))
- p attribute
- p self.send(attribute)
- end
-
- # Removes non-serializable data. Allowed data types are strings, arrays,
- # and hashes. All other types are converted to strings.
- # TODO: move this onto Hash
- def clean_unserializable_data(data, stack = [])
+ # Detects if there are any infinite loops in the hash
+ def detect_loops(data, stack = [])
return "[possible infinite recursion halted]" if stack.any?{|item| item == data.object_id }
-
if data.respond_to?(:to_hash)
- data.to_hash.inject({}) do |result, (key, value)|
- result.merge(key => clean_unserializable_data(value, stack + [data.object_id]))
- end
- elsif data.respond_to?(:to_ary)
- data.collect do |value|
- clean_unserializable_data(value, stack + [data.object_id])
+ data.to_hash.each do |k,v|
+ data[k] = detect_loops(v, [data.object_id] + stack)
end
- else
- xml_value_for(data)
- end
- end
-
- def xml_value_for(value)
- if inspectable?(value)
- value.inspect
- else
- value.to_s
- end
- end
-
- def inspectable?(value)
- case value
- when Fixnum, Array, nil, IO
- true
- else
- false
end
+ data
end
# Replaces the contents of params that match params_filters.
# TODO: extract this to a different class
- def clean_params
- clean_unserializable_data_from(:parameters)
+ def filter_params
+ detect_loops(parameters)
filter(parameters)
if cgi_data
- clean_unserializable_data_from(:cgi_data)
+ detect_loops(cgi_data)
filter(cgi_data)
end
if session_data
- clean_unserializable_data_from(:session_data)
+ detect_loops(session_data)
filter(session_data)
end
end
@@ -291,7 +258,7 @@ def clean_rack_request_data
def filter(hash)
if params_filters
- hash.each do |key, value|
+ hash.to_hash.each do |key, value|
if filter_key?(key)
hash[key] = "[FILTERED]"
elsif value.respond_to?(:to_hash)
View
67 lib/hoptoad_notifier/xml_var_generator.rb
@@ -0,0 +1,67 @@
+module HoptoadNotifier
+ class XmlVarGenerator
+ def initialize(params)
+ @params = params
+ end
+
+ def build(builder)
+ @params.each do |key, value|
+ Generic.get(value).build(builder, key)
+ end
+ builder
+ end
+
+ class Generic
+ def self.serialize(value)
+ get(value).serialize
+ end
+
+ def self.get(value)
+ klass = @subclasses.select{|c| value.is_a?(c.for_class) }.first || Generic
+ klass.new(value)
+ end
+
+ def self.inherited(other)
+ (@subclasses ||= []) << other
+ end
+
+ def initialize(value)
+ @value = value
+ end
+
+ def build(builder, key = nil)
+ builder.var(serialize, :key => key)
+ end
+
+ def serialize
+ @value.to_s
+ end
+ end
+
+ class Hash < Generic
+ def self.for_class; ::Hash; end
+
+ def build(builder, key = nil)
+ builder.var(:key => key) do |subhash|
+ XmlVarGenerator.new(@value).build(subhash)
+ end
+ end
+ end
+
+ class Array < Generic
+ def self.for_class; ::Array; end
+
+ def serialize
+ @value.inspect
+ end
+ end
+
+ class File < Generic
+ def self.for_class; ::File; end
+
+ def serialize
+ @value.inspect
+ end
+ end
+ end
+end
View
14 test/catcher_test.rb
@@ -31,23 +31,13 @@ def assert_sent_hash(hash, xpath)
if value.respond_to?(:to_hash)
assert_sent_hash value.to_hash, element_xpath
else
- assert_sent_element value, element_xpath
+ assert_sent_element HoptoadNotifier::XmlVarGenerator::Generic.serialize(value), element_xpath
end
end
end
def assert_sent_element(value, xpath)
- assert_valid_node last_sent_notice_document, xpath, stringify_array_elements(value).to_s
- end
-
- def stringify_array_elements(data)
- if data.respond_to?(:to_ary)
- data.collect do |value|
- stringify_array_elements(value)
- end
- else
- data.to_s
- end
+ assert_valid_node last_sent_notice_document, xpath, value
end
def assert_sent_request_info_for(request)
View
3  test/helper.rb
@@ -1,5 +1,6 @@
require 'test/unit'
require 'rubygems'
+require 'pp'
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
@@ -172,7 +173,7 @@ def assert_array_starts_with(expected, actual)
def assert_valid_node(document, xpath, content)
nodes = document.xpath(xpath)
- assert nodes.any?{|node| node.content == content },
+ assert nodes.any?{|node| node.content == content || node.content =~ Regexp.new(content.to_s) },
"Expected xpath #{xpath} to have content #{content}, " +
"but found #{nodes.map { |n| n.content }} in #{nodes.size} matching nodes.\n" +
"Document:\n#{document.to_s}"
View
42 test/notice_test.rb
@@ -155,12 +155,6 @@ def stub_request(attrs = {})
assert_array_starts_with backtrace.lines, notice.backtrace.lines
end
- should "convert unserializable objects to strings" do
- assert_serializes_hash(:parameters)
- assert_serializes_hash(:cgi_data)
- assert_serializes_hash(:session_data)
- end
-
should "filter parameters" do
assert_filters_hash(:parameters)
end
@@ -418,42 +412,6 @@ def assert_accepts_exception_attribute(attribute, args = {}, &block)
"#{attribute} was not correctly set from a hash"
end
- def assert_serializes_hash(attribute)
- [File.open(__FILE__), Proc.new { puts "boo!" }, Module.new].each do |object|
- hash = {
- :strange_object => object,
- :sub_hash => {
- :sub_object => object
- },
- :array => [object]
- }
- notice = build_notice(attribute => hash)
- hash = notice.send(attribute)
- assert_equal xml_value_for(object), hash[:strange_object], "objects should be serialized"
- assert_kind_of Hash, hash[:sub_hash], "subhashes should be kept"
- assert_equal xml_value_for(object), hash[:sub_hash][:sub_object], "subhash members should be serialized"
- assert_kind_of Array, hash[:array], "arrays should be kept"
- assert_equal xml_value_for(object), hash[:array].first, "array members should be serialized"
- end
- end
-
- def xml_value_for(value)
- if inspectable?(value)
- value.inspect
- else
- value.to_s
- end
- end
-
- def inspectable?(value)
- case value
- when Fixnum, Array, nil, IO
- true
- else
- false
- end
- end
-
def assert_valid_notice_document(document)
xsd_path = File.join(File.dirname(__FILE__), "hoptoad_2_2.xsd")
schema = Nokogiri::XML::Schema.new(IO.read(xsd_path))
View
73 test/xml_var_generator_test.rb
@@ -0,0 +1,73 @@
+require File.dirname(__FILE__) + '/helper'
+
+class XmlVarGeneratorTest < Test::Unit::TestCase
+ context "given a hash of values" do
+ setup do
+ @generator = HoptoadNotifier::XmlVarGenerator.new(
+ :string => "a string",
+ :integer => 3,
+ :float => 2.718281828,
+ :subhash => {
+ :substring => "a substring",
+ :subsubarray => [ 1, 2, "3" ]
+ },
+ :subarray => ["hello", 3],
+ :object => Module.new
+ )
+ builder = Builder::XmlMarkup.new
+ builder.container do |container|
+ @generator.build(container)
+ end
+ xml = builder.to_s
+ @document = Nokogiri::XML::Document.parse(xml)
+ end
+
+ should "output a lonely string" do
+ assert_valid_node(@document,
+ "//var[@key='string']",
+ "a string")
+ end
+
+ should "output an integer" do
+ assert_valid_node(@document,
+ "//var[@key='integer']",
+ '3')
+ end
+
+ should "output a float" do
+ assert_valid_node(@document,
+ "//var[@key='float']",
+ '2.718281828')
+ end
+
+ should "output a subhash" do
+ assert_valid_node(@document,
+ "//var/@key",
+ "subhash")
+ end
+
+ should "output a string in a subhash" do
+ assert_valid_node(@document,
+ "//var[@key='subhash']/var[@key='substring']",
+ "a substring")
+ end
+
+ should "output an array, inspecting the contents" do
+ assert_valid_node(@document,
+ "//var[@key='subarray']",
+ '["hello", 3]')
+ end
+
+ should "output an subarray, inspecting the contents" do
+ assert_valid_node(@document,
+ "//var[@key='subhash']/var[@key='subsubarray']",
+ '[1, 2, "3"]')
+ end
+
+ should "output generic objects" do
+ assert_valid_node(@document,
+ "//var[@key='object']",
+ /#<Module:0x[0-9a-f]+>/)
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.