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 @failure_message end |
#message ⇒ Object
Returns the value of attribute message.
71 72 73 |
# File 'lib/assert2/xhtml.rb', line 71 def @message 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
110 111 112 113 114 |
# File 'lib/assert2/xhtml.rb', line 110 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
283 284 285 |
# File 'lib/assert2/xhtml.rb', line 283 def build_deep_xpath_too(element) return '//' + build_xpath_too(element) end |
#build_predicate(element, conjunction = 'and') ⇒ Object
140 141 142 143 144 |
# File 'lib/assert2/xhtml.rb', line 140 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
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/assert2/xhtml.rb', line 116 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
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/assert2/xhtml.rb', line 287 def build_xpath_too(element) path = element.name.sub(/\!$/, '') element_kids = element.children.grep(Nokogiri::XML::Node) 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
261 262 263 264 265 266 267 |
# File 'lib/assert2/xhtml.rb', line 261 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?
168 169 170 171 172 173 174 175 |
# File 'lib/assert2/xhtml.rb', line 168 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
273 274 275 276 277 278 279 280 281 |
# File 'lib/assert2/xhtml.rb', line 273 def complain( refered = @builder.doc, sample = @best_sample || @doc.root ) # ERGO use to_xml? or what? @failure_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
232 233 234 |
# File 'lib/assert2/xhtml.rb', line 232 def deAmpAmp(stwing) stwing.to_s.gsub('&amp;', '&').gsub('&', '&') end |
#depth(e) ⇒ Object
269 270 271 |
# File 'lib/assert2/xhtml.rb', line 269 def depth(e) e.xpath('ancestor-or-self::*').length end |
#elemental_children(element = @builder.doc) ⇒ Object
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/assert2/xhtml.rb', line 99 def elemental_children(element = @builder.doc) element_kids = element.children.grep(Nokogiri::XML::Node) element_kids = element_kids.reject{|k| k.class == Nokogiri::XML::Text || k.class == Nokogiri::XML::DTD } # CONSIDER rebuild to use not abuse the text nodage! return element_kids end |
#get_texts(element) ⇒ Object
256 257 258 259 |
# File 'lib/assert2/xhtml.rb', line 256 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
225 226 227 228 229 230 |
# File 'lib/assert2/xhtml.rb', line 225 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?
184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/assert2/xhtml.rb', line 184 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
177 178 179 180 |
# File 'lib/assert2/xhtml.rb', line 177 def match_attributes_and_text(reference, sample) @reference, @sample = reference, sample match_attributes and match_text end |
#match_class(attr_name, ref, sam) ⇒ Object
241 242 243 244 |
# File 'lib/assert2/xhtml.rb', line 241 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; !!!
236 237 238 239 |
# File 'lib/assert2/xhtml.rb', line 236 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!
247 248 249 250 251 252 253 254 |
# File 'lib/assert2/xhtml.rb', line 247 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 got = (ref_text.length == 1 and match_regexp(ref_text.first, sam_text.join)) return got end |
#match_xpath(path, &refer) ⇒ Object
157 158 159 160 161 162 163 164 |
# File 'lib/assert2/xhtml.rb', line 157 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??
216 217 218 219 220 221 222 223 |
# File 'lib/assert2/xhtml.rb', line 216 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
311 312 313 |
# File 'lib/assert2/xhtml.rb', line 311 def "please don't negate - use without!" end |
#run_all_xpaths(xpaths) ⇒ Object
146 147 148 149 150 151 152 153 154 155 |
# File 'lib/assert2/xhtml.rb', line 146 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
196 197 198 199 200 201 202 |
# File 'lib/assert2/xhtml.rb', line 196 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
132 133 134 135 136 137 138 |
# File 'lib/assert2/xhtml.rb', line 132 def translate_tag(element) if element.name == 'any!' '*' else element.name.sub(/\!$/, '') end end |
#verbose_spew(attr) ⇒ Object
204 205 206 207 208 209 210 211 212 |
# File 'lib/assert2/xhtml.rb', line 204 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 |