Class: BeHtmlWith
- Inherits:
-
Object
- Object
- BeHtmlWith
- Defined in:
- lib/assert2/xhtml.rb
Instance Attribute Summary collapse
-
#builder ⇒ Object
Returns the value of attribute builder.
-
#doc ⇒ Object
Returns the value of attribute doc.
-
#failure_message ⇒ Object
Returns the value of attribute failure_message.
-
#message ⇒ Object
Returns the value of attribute message.
-
#reference ⇒ Object
Returns the value of attribute reference.
-
#references ⇒ Object
Returns the value of attribute references.
-
#returnable ⇒ Object
Returns the value of attribute returnable.
-
#sample ⇒ Object
Returns the value of attribute sample.
-
#scope ⇒ Object
Returns the value of attribute scope.
Instance Method Summary collapse
- #build_deep_xpath(element) ⇒ Object
- #build_deep_xpath_too(element) ⇒ Object
- #build_predicate(element, conjunction = 'and') ⇒ Object
- #build_xpath(element) ⇒ Object
- #build_xpath_too(element) ⇒ Object
- #build_xpaths(&block) ⇒ Object
- #collect_best_sample(samples) ⇒ Object
-
#collect_samples(elements, index) ⇒ Object
ERGO match text with internal spacies?.
- #complain(refered = @builder.doc, sample = @best_sample || @doc.root) ⇒ Object
- #deAmpAmp(stwing) ⇒ Object
- #depth(e) ⇒ Object
- #elemental_children(element = @builder.doc) ⇒ Object
- #get_texts(element) ⇒ Object
-
#initialize(scope, &block) ⇒ BeHtmlWith
constructor
A new instance of BeHtmlWith.
- #match_attribute(attr) ⇒ Object
-
#match_attributes ⇒ Object
TODO uh, indenting mebbe?.
- #match_attributes_and_text(reference, sample) ⇒ Object
- #match_class(attr_name, ref, sam) ⇒ Object
-
#match_regexp(reference, sample) ⇒ Object
ERGO await a fix in Nokogiri, and hope nobody actually means & !!!.
-
#match_text(ref = @reference, sam = @sample) ⇒ Object
NOTE if you call it a class, but ref contains something fruity, you are on your own!.
- #match_xpath(path, &refer) ⇒ Object
-
#match_xpath_predicate(attr) ⇒ Object
TODO why we have no :css! yet??.
- #matches?(stwing, &block) ⇒ Boolean
- #negative_failure_message ⇒ Object
- #run_all_xpaths(xpaths) ⇒ Object
- #sort_nodes ⇒ Object
- #translate_tag(element) ⇒ Object
- #verbose_spew(attr) ⇒ Object
Constructor Details
#initialize(scope, &block) ⇒ BeHtmlWith
Returns a new instance of BeHtmlWith.
65 66 67 68 69 |
# File 'lib/assert2/xhtml.rb', line 65 def initialize(scope, &block) @scope, @block = scope, block @references = [] @spewed = {} end |
Instance Attribute Details
#builder ⇒ Object
Returns the value of attribute builder.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def builder @builder end |
#doc ⇒ Object
Returns the value of attribute doc.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def doc @doc end |
#failure_message ⇒ Object
Returns the value of attribute failure_message.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def end |
#message ⇒ Object
Returns the value of attribute message.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def end |
#reference ⇒ Object
Returns the value of attribute reference.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def reference @reference end |
#references ⇒ Object
Returns the value of attribute references.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def references @references end |
#returnable ⇒ Object
Returns the value of attribute returnable.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def returnable @returnable end |
#sample ⇒ Object
Returns the value of attribute sample.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def sample @sample end |
#scope ⇒ Object
Returns the value of attribute scope.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def scope @scope end |
Instance Method Details
#build_deep_xpath(element) ⇒ Object
103 104 105 106 107 |
# File 'lib/assert2/xhtml.rb', line 103 def build_deep_xpath(element) path = build_xpath(element) path.index('not(') == 0 and return '/*[ ' + path + ' ]' return '//' + path end |
#build_deep_xpath_too(element) ⇒ Object
275 276 277 |
# File 'lib/assert2/xhtml.rb', line 275 def build_deep_xpath_too(element) return '//' + build_xpath_too(element) end |
#build_predicate(element, conjunction = 'and') ⇒ Object
133 134 135 136 137 |
# File 'lib/assert2/xhtml.rb', line 133 def build_predicate(element, conjunction = 'and') conjunction = " #{ conjunction } " element_kids = elemental_children(element) return element_kids.map{|child| build_xpath(child) }.join(conjunction) end |
#build_xpath(element) ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/assert2/xhtml.rb', line 109 def build_xpath(element) count = @references.length @references << element # note we skip the without @reference! if element.name == 'without!' return 'not( ' + build_predicate(element, 'or') + ' )' else target = translate_tag(element) path = "descendant::#{ target }[ refer(., '#{ count }') " # refer() is first so we collect many samples, despite boolean short-circuiting path << 'and ' if elemental_children(element).any? path << build_predicate(element) + ']' return path end end |
#build_xpath_too(element) ⇒ Object
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/assert2/xhtml.rb', line 279 def build_xpath_too(element) path = element.name.sub(/\!$/, '') element_kids = element.children.grep(Nokogiri::XML::Element) path << '[ ' count = @references.length @references << element brackets_owed = 0 if element_kids.length > 0 child = element_kids[0] path << './descendant::' + build_xpath_too(child) end if element_kids.length > 1 path << element_kids[1..-1].map{|child| '[ ./following-sibling::*[ ./descendant-or-self::' + build_xpath_too(child) + ' ] ]' }.join #(' and .') end path << ' and ' if element_kids.any? path << "refer(., '#{ count }') ]" # last so boolean short-circuiting optimizes return path end |
#build_xpaths(&block) ⇒ Object
90 91 92 93 94 95 96 97 |
# File 'lib/assert2/xhtml.rb', line 90 def build_xpaths(&block) bwock = block || @block || proc{} # CONSIDER what to do with no block? validate? @builder = Nokogiri::HTML::Builder.new(&bwock) elemental_children.map do |child| build_deep_xpath(child) end end |
#collect_best_sample(samples) ⇒ Object
253 254 255 256 257 258 259 |
# File 'lib/assert2/xhtml.rb', line 253 def collect_best_sample(samples) sample = samples.first or return if @best_sample.nil? or depth(@best_sample) > depth(sample) @best_sample = sample end end |
#collect_samples(elements, index) ⇒ Object
ERGO match text with internal spacies?
161 162 163 164 165 166 167 168 |
# File 'lib/assert2/xhtml.rb', line 161 def collect_samples(elements, index) # TODO rename these samples to specimens samples = elements.find_all do |element| match_attributes_and_text(@references[index], element) end collect_best_sample(samples) samples end |
#complain(refered = @builder.doc, sample = @best_sample || @doc.root) ⇒ Object
265 266 267 268 269 270 271 272 273 |
# File 'lib/assert2/xhtml.rb', line 265 def complain( refered = @builder.doc, sample = @best_sample || @doc.root ) # ERGO use to_xml? or what? = "#{message}\n".lstrip + "\nCould not find this reference...\n\n" + refered.to_xhtml.sub(/^\<\!DOCTYPE.*/, '') + "\n\n...in this sample...\n\n" + sample.to_xml end |
#deAmpAmp(stwing) ⇒ Object
225 226 227 |
# File 'lib/assert2/xhtml.rb', line 225 def deAmpAmp(stwing) stwing.to_s.gsub('&amp;', '&').gsub('&', '&') end |
#depth(e) ⇒ Object
261 262 263 |
# File 'lib/assert2/xhtml.rb', line 261 def depth(e) e.xpath('ancestor-or-self::*').length end |
#elemental_children(element = @builder.doc) ⇒ Object
99 100 101 |
# File 'lib/assert2/xhtml.rb', line 99 def elemental_children(element = @builder.doc) element.children.grep(Nokogiri::XML::Element) end |
#get_texts(element) ⇒ Object
248 249 250 251 |
# File 'lib/assert2/xhtml.rb', line 248 def get_texts(element) element.children.grep(Nokogiri::XML::Text). map{|x|x.to_s.strip}.select{|x|x.any?} end |
#match_attribute(attr) ⇒ Object
218 219 220 221 222 223 |
# File 'lib/assert2/xhtml.rb', line 218 def match_attribute(attr) ref = deAmpAmp(attr.value) sam = deAmpAmp(@sample[attr.name]) ref == sam or match_regexp(ref, sam) or match_class(attr.name, ref, sam) end |
#match_attributes ⇒ Object
TODO uh, indenting mebbe?
177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/assert2/xhtml.rb', line 177 def match_attributes sort_nodes.each do |attr| case attr.name when 'verbose!' ; verbose_spew(attr) when 'xpath!' ; match_xpath_predicate(attr) or return false else ; match_attribute(attr) or return false end end return true end |
#match_attributes_and_text(reference, sample) ⇒ Object
170 171 172 173 |
# File 'lib/assert2/xhtml.rb', line 170 def match_attributes_and_text(reference, sample) @reference, @sample = reference, sample match_attributes and match_text end |
#match_class(attr_name, ref, sam) ⇒ Object
234 235 236 237 |
# File 'lib/assert2/xhtml.rb', line 234 def match_class(attr_name, ref, sam) attr_name == 'class' and " #{ sam } ".index(" #{ ref } ") end |
#match_regexp(reference, sample) ⇒ Object
ERGO await a fix in Nokogiri, and hope nobody actually means &amp; !!!
229 230 231 232 |
# File 'lib/assert2/xhtml.rb', line 229 def match_regexp(reference, sample) reference =~ /\(\?.*\)/ and # the irony _is_ lost on us... Regexp.new(reference) =~ sample end |
#match_text(ref = @reference, sam = @sample) ⇒ Object
NOTE if you call it a class, but ref contains
something fruity, you are on your own!
240 241 242 243 244 245 246 |
# File 'lib/assert2/xhtml.rb', line 240 def match_text(ref = @reference, sam = @sample) ref_text = get_texts(ref) ref_text.empty? and return true sam_text = get_texts(sam) (ref_text - sam_text).empty? and return true ref_text.length == 1 and match_regexp(ref_text.first, sam_text.join) end |
#match_xpath(path, &refer) ⇒ Object
150 151 152 153 154 155 156 157 |
# File 'lib/assert2/xhtml.rb', line 150 def match_xpath(path, &refer) nodes = @doc.root.xpath_with_callback path, :refer do |element, index| collect_samples(element, index.to_i) end @returnable ||= nodes.first # TODO be_with_html must get on board too return nodes end |
#match_xpath_predicate(attr) ⇒ Object
TODO why we have no :css! yet??
209 210 211 212 213 214 215 216 |
# File 'lib/assert2/xhtml.rb', line 209 def match_xpath_predicate(attr) @sample.parent.xpath("*[ #{ attr.value } ]").each do |m| m.path == @sample.path and return true end return false end |
#matches?(stwing, &block) ⇒ Boolean
81 82 83 84 85 86 87 88 |
# File 'lib/assert2/xhtml.rb', line 81 def matches?(stwing, &block) @block ||= block # ERGO test that ||= - preferrably with a real RSpec suite! @scope.wrap_expectation self do @doc = Nokogiri::HTML(stwing) return run_all_xpaths(build_xpaths) end end |
#negative_failure_message ⇒ Object
303 304 305 |
# File 'lib/assert2/xhtml.rb', line 303 def "please don't negate - use without!" end |
#run_all_xpaths(xpaths) ⇒ Object
139 140 141 142 143 144 145 146 147 148 |
# File 'lib/assert2/xhtml.rb', line 139 def run_all_xpaths(xpaths) xpaths.each do |path| if match_xpath(path).empty? complain return false end end return true end |
#sort_nodes ⇒ Object
189 190 191 192 193 194 195 |
# File 'lib/assert2/xhtml.rb', line 189 def sort_nodes @reference.attribute_nodes.sort_by do |q| { 'verbose!' => 0, # put this first, so it always runs, even if attributes don't match 'xpath!' => 2 # put this last, so if attributes don't match, it does not waste time }.fetch(q.name, 1) end end |
#translate_tag(element) ⇒ Object
125 126 127 128 129 130 131 |
# File 'lib/assert2/xhtml.rb', line 125 def translate_tag(element) if element.name == 'any!' '*' else element.name.sub(/\!$/, '') end end |
#verbose_spew(attr) ⇒ Object
197 198 199 200 201 202 203 204 205 |
# File 'lib/assert2/xhtml.rb', line 197 def verbose_spew(attr) if attr.value == 'true' and @spewed[yo_path = @sample.path] == nil puts puts '-' * 60 p yo_path puts @sample.to_xhtml @spewed[yo_path] = true end end |