crazy_harry 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
 - data/Gemfile +6 -0
 - data/Guardfile +10 -0
 - data/README.md +116 -0
 - data/Rakefile +6 -0
 - data/crazy_harry.gemspec +28 -0
 - data/lib/crazy_harry.rb +27 -0
 - data/lib/crazy_harry/base.rb +31 -0
 - data/lib/crazy_harry/change.rb +59 -0
 - data/lib/crazy_harry/default.rb +67 -0
 - data/lib/crazy_harry/redact.rb +73 -0
 - data/lib/crazy_harry/translate.rb +56 -0
 - data/lib/crazy_harry/version.rb +3 -0
 - data/rvmrc.example +1 -0
 - data/spec/fixtures/golden_nugget.html +50 -0
 - data/spec/fixtures/golden_nugget_corrected.html +24 -0
 - data/spec/integration/crazy_harry_spec.rb +23 -0
 - data/spec/lib/change_spec.rb +83 -0
 - data/spec/lib/crazy_harry_spec.rb +86 -0
 - data/spec/lib/redact_spec.rb +122 -0
 - data/spec/lib/translate_spec.rb +46 -0
 - data/spec/spec_helper.rb +12 -0
 - metadata +130 -0
 
    
        data/.gitignore
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/Guardfile
    ADDED
    
    | 
         @@ -0,0 +1,10 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # A sample Guardfile
         
     | 
| 
      
 2 
     | 
    
         
            +
            # More info at https://github.com/guard/guard#readme
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            guard 'rspec', :version => 2, :cli => '--color' do
         
     | 
| 
      
 5 
     | 
    
         
            +
              watch(%r{^spec/.+_spec\.rb$})
         
     | 
| 
      
 6 
     | 
    
         
            +
              watch(%r{^lib/crazy_harry/(.+)\.rb$})   { |m| ["spec/lib/crazy_harry/#{m[1]}_spec.rb", "spec/integration/crazy_harry/#{m[1]}_spec.rb", "spec/lib/crazy_harry_spec.rb"] }
         
     | 
| 
      
 7 
     | 
    
         
            +
              watch(%r{^lib/(.+)\.rb$})               { |m| ["spec/lib/#{m[1]}_spec.rb", "spec/integration/#{m[1]}_spec.rb"] }
         
     | 
| 
      
 8 
     | 
    
         
            +
              watch('spec/spec_helper.rb')            { "spec" }
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,116 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # CrazyHarry
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            [](http://travis-ci.org/lonelyplanet/crazy_harry)
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            CrazyHarry is a high-level html fragment sanitiser/cleaner in use at
         
     | 
| 
      
 6 
     | 
    
         
            +
            [Lonely Planet](http://www.lonelyplanet.com).  It is based on [Flavour
         
     | 
| 
      
 7 
     | 
    
         
            +
            Jones's](http://mike.daless.io) [Loofah Gem](https://github.com/flavorjones). 
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            [Loofah](https://github.com/flavorjones) is a great tool and we've been
         
     | 
| 
      
 10 
     | 
    
         
            +
            using it in a number of different projects.  Hoewever, we found that we
         
     | 
| 
      
 11 
     | 
    
         
            +
            were repeating the same types of cleaning job in multiple places. 
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            CrazyHarry wraps up a number these tasks in a simple DSL, while adding commands for a few edge cases that are not straightforward with Loofah.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            ## Installation 
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                gem 'crazy_harry' 
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                bundle install 
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                object_with_description.each do |obj|
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  if descriptions[l.external_id]
         
     | 
| 
      
 26 
     | 
    
         
            +
                    sanitised_fragment = CrazyHarry.fragment(descriptions[obj.external_id])
         
     | 
| 
      
 27 
     | 
    
         
            +
                      .redact!( unsafe: true,     tags: 'img')
         
     | 
| 
      
 28 
     | 
    
         
            +
                      .change!( from: 'b',        to: 'h3' )
         
     | 
| 
      
 29 
     | 
    
         
            +
                      .change!( from: 'strong',   to: 'h3' )
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    obj.update_column(:description, sanitised_fragment.to_s)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            ## Default Actions
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            It automatically removes blank tags, converts `<br \>` tags to wrapped
         
     | 
| 
      
 38 
     | 
    
         
            +
            paragraphs and de-dupes content.  
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            ## Chaining
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            As per the previous example, all calls **except** `.strip!` (which removes
         
     | 
| 
      
 43 
     | 
    
         
            +
            all markup) may be chained.  (`.strip!` can be the last element in a
         
     | 
| 
      
 44 
     | 
    
         
            +
            chain.  See below). 
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            ## Scoping and Targeting by Content
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            All commands except `.strip!` accept `scope:` and `text:` attributes:
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                CrazyHarry.fragment( '<div><b>Hotels</b></div><p><b>Hotels</b></p><b>Tents</b>' ).change!( from: 'b', to: 'em', scope: 'p' ).to_s
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            will produce: 
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                <div><b>Hotels</b></div><p><em>Hotels</em></p><b>Tents</b>
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            while:
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                CrazyHarry.fragment( 'Hot <b>hotels</b> in <b>Saigon</b>' ).change!( from: 'b', to: 'em', text: 'hotels' ).to_s
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            will produce:
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                Hot <em>hotels</em> in <b>Saigon</b>
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            ## Adding Attributes
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            Use the `.translate` command to do this:
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                harry.fragment( '<b>Header</b><p>Content</p>' ).translate!( add_attributes: { class: 'partner'} ).to_s
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            will return:
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                <b class="partner">Header</b><p class="partner">Content</p>
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
            If a tag already has an attribute, the new attribute will be appended to
         
     | 
| 
      
 76 
     | 
    
         
            +
            the existing one:
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                <b class="bright-red partner">Header</b><p class="partner">Content</p>
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
            ## Stripping
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
            ### Specific Tags
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            Use the `.redact!` command.  It **does not** strip unsafe tags by default.
         
     | 
| 
      
 85 
     | 
    
         
            +
            To do this, pass the `unsafe: true` option.
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
            ### All Tags
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            Use the `.strip!` command.  It can be used as the last tag in a chain
         
     | 
| 
      
 90 
     | 
    
         
            +
            (with `.translate( from_text: <some text>, to_text: <other text> )`, for instance), but should generally be the only call
         
     | 
| 
      
 91 
     | 
    
         
            +
            you make. 
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            ## Text Translation 
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            The `.translate!` command can change tag content, preserving case:
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                CrazyHarry.fragment( '<h3>Lodging</h3> lodging' ).translate!( from_text: 'lodging', to_text: 'hotel' ).to_s
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
            will return:
         
     | 
| 
      
 100 
     | 
    
         
            +
             
         
     | 
| 
      
 101 
     | 
    
         
            +
                <h3>Hotel</h3> lodging
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            ## Known Issues/TODO
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
              * De-duping does not take account of whitespace.  So, `<p>Some Content</p>` and `<p>Some Content </p>` will not be treated as duplicates.
         
     | 
| 
      
 106 
     | 
    
         
            +
              * Be able to turn off default actions.
         
     | 
| 
      
 107 
     | 
    
         
            +
              * It should be able to work on documents as well as fragments.
         
     | 
| 
      
 108 
     | 
    
         
            +
              * Merge `.translate!` with `.change!` 
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
              1. Fork it
         
     | 
| 
      
 113 
     | 
    
         
            +
              2. Create your feature branch (`git checkout -b my-new-feature`)
         
     | 
| 
      
 114 
     | 
    
         
            +
              3. Commit your changes (`git commit -am 'Added some feature'`)
         
     | 
| 
      
 115 
     | 
    
         
            +
              4. Push to the branch (`git push origin my-new-feature`)
         
     | 
| 
      
 116 
     | 
    
         
            +
              5. Create new Pull Request
         
     | 
    
        data/Rakefile
    ADDED
    
    
    
        data/crazy_harry.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- encoding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            $:.push File.expand_path("../lib", __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "crazy_harry/version"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.name        = "crazy_harry"
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.version     = CrazyHarry::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.authors     = ["TA Tyree"]
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.email       = ["todd.tyree@lonelyplanet.co.uk"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.homepage    = "https://github.com/lonelyplanet/crazy_harry"
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.summary     = %q{A High level HTML fragment sanitizer.}
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.description = %q{CrazyHarry is a high-level html fragment sanitiser/cleaner based on Loofah.}
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              s.rubyforge_project = "crazy_harry"
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              s.files         = `git ls-files`.split("\n")
         
     | 
| 
      
 17 
     | 
    
         
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         
     | 
| 
      
 19 
     | 
    
         
            +
              s.require_paths = ["lib"]
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              # specify any dependencies here; for example:
         
     | 
| 
      
 22 
     | 
    
         
            +
              s.add_development_dependency 'rspec'
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.add_development_dependency 'guard'
         
     | 
| 
      
 24 
     | 
    
         
            +
              s.add_development_dependency 'guard-rspec'
         
     | 
| 
      
 25 
     | 
    
         
            +
              s.add_development_dependency 'simplecov'
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              s.add_runtime_dependency 'loofah'
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/crazy_harry.rb
    ADDED
    
    | 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'loofah'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            %w(default change redact translate base version).each do |load_lib|
         
     | 
| 
      
 4 
     | 
    
         
            +
              require_relative "crazy_harry/#{load_lib}"
         
     | 
| 
      
 5 
     | 
    
         
            +
            end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module CrazyHarry
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              attr_accessor :base
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def fragment(fragment)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  base = Base.new(fragment: fragment)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  base.no_blanks!
         
     | 
| 
      
 16 
     | 
    
         
            +
                  base.convert_br_to_p!
         
     | 
| 
      
 17 
     | 
    
         
            +
                  base.dedupe!
         
     | 
| 
      
 18 
     | 
    
         
            +
                  base
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @base.to_s
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CrazyHarry
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                include CrazyHarry::Default
         
     | 
| 
      
 4 
     | 
    
         
            +
                include CrazyHarry::Change
         
     | 
| 
      
 5 
     | 
    
         
            +
                include CrazyHarry::Redact
         
     | 
| 
      
 6 
     | 
    
         
            +
                include CrazyHarry::Translate
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                attr_accessor :fragment, :scope, :steps, :text
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def initialize(opts = {})
         
     | 
| 
      
 11 
     | 
    
         
            +
                  self.fragment = Loofah.fragment(opts.delete(:fragment)) if opts.has_key?(:fragment)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  self.steps = []
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 16 
     | 
    
         
            +
                  self.fragment.to_s.squeeze(' ').strip
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                private
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def run!
         
     | 
| 
      
 22 
     | 
    
         
            +
                  steps.compact.delete_if do |step|
         
     | 
| 
      
 23 
     | 
    
         
            +
                    if steps.size > 0
         
     | 
| 
      
 24 
     | 
    
         
            +
                      fragment.scrub!(step)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      true
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,59 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CrazyHarry
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Change
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                BLOCK_CONVERSION_ELEMENTS = {
         
     | 
| 
      
 5 
     | 
    
         
            +
                  inlines:  %w(br),
         
     | 
| 
      
 6 
     | 
    
         
            +
                  blocks:   %w(div p)
         
     | 
| 
      
 7 
     | 
    
         
            +
                }
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                attr_accessor :from, :to
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def change!(opts)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  self.from  =  opts.delete(:from)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  self.to    =  opts.delete(:to)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  self.text  =  opts.delete(:text)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  self.scope =  opts.delete(:scope)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  self.steps << generic_from_to
         
     | 
| 
      
 18 
     | 
    
         
            +
                  self.steps << unwrap_unnecessary_paragraphs
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  run!
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  self
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                private
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def change_this_node?(node)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  ( self.text       ? node.text == self.text                          : true ) &&
         
     | 
| 
      
 29 
     | 
    
         
            +
                  ( self.scope      ? node.parent.name == self.scope                  : true ) &&
         
     | 
| 
      
 30 
     | 
    
         
            +
                  ( node.name == self.from )
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def convert_inline_element_to_block?
         
     | 
| 
      
 34 
     | 
    
         
            +
                  BLOCK_CONVERSION_ELEMENTS[:inlines].include?(self.from) &&
         
     | 
| 
      
 35 
     | 
    
         
            +
                  BLOCK_CONVERSION_ELEMENTS[:blocks].include?(self.to)
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def generic_from_to
         
     | 
| 
      
 39 
     | 
    
         
            +
                  return if convert_inline_element_to_block?
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  Loofah::Scrubber.new do |node|
         
     | 
| 
      
 42 
     | 
    
         
            +
                    node.name = self.to if change_this_node?(node)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def unwrap_unnecessary_paragraphs
         
     | 
| 
      
 47 
     | 
    
         
            +
                  Loofah::Scrubber.new do |node|
         
     | 
| 
      
 48 
     | 
    
         
            +
                    node.replace(node.children.first) if unnecessary_paragraph?(node)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def unnecessary_paragraph?(node)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  node.name == 'p' &&
         
     | 
| 
      
 54 
     | 
    
         
            +
                  node.children.size == 1 &&
         
     | 
| 
      
 55 
     | 
    
         
            +
                  Loofah::Elements::BLOCK_LEVEL.include?(node.children.first.name)
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,67 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CrazyHarry
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Default
         
     | 
| 
      
 3 
     | 
    
         
            +
                TARGET_ELEMENTS = ['b'].to_set 
         
     | 
| 
      
 4 
     | 
    
         
            +
                TARGET_ELEMENTS.merge(Loofah::Elements::BLOCK_LEVEL)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def no_blanks! 
         
     | 
| 
      
 7 
     | 
    
         
            +
                  self.steps << remove_blank_elements
         
     | 
| 
      
 8 
     | 
    
         
            +
                  run!
         
     | 
| 
      
 9 
     | 
    
         
            +
                  self
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def dedupe!
         
     | 
| 
      
 13 
     | 
    
         
            +
                  self.fragment = Loofah.fragment(html_with_duplicates_removed_from_the_bottom_up)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  self
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def convert_br_to_p!
         
     | 
| 
      
 18 
     | 
    
         
            +
                  fragment.xpath('br/following-sibling::text()|br/preceding-sibling::text()').each do |node|
         
     | 
| 
      
 19 
     | 
    
         
            +
                    node.replace(Nokogiri.make("<p>#{node.to_html.strip}</p>")) unless node.content =~ /\A\s*\z/
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  fragment.scrub!(scrub_tag('br'))
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                private
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def scrub_tag(tag_name)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  Loofah::Scrubber.new do |node|
         
     | 
| 
      
 29 
     | 
    
         
            +
                    if node.name == tag_name
         
     | 
| 
      
 30 
     | 
    
         
            +
                      node.remove
         
     | 
| 
      
 31 
     | 
    
         
            +
                      Loofah::Scrubber::STOP # don't bother with the rest of the subtree
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def this_element?(element)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  name = element.respond_to?(:name) ? element.name : element
         
     | 
| 
      
 38 
     | 
    
         
            +
                  TARGET_ELEMENTS.include?(name) 
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def remove_blank_elements
         
     | 
| 
      
 42 
     | 
    
         
            +
                  Loofah::Scrubber.new do |node|
         
     | 
| 
      
 43 
     | 
    
         
            +
                    node.remove if this_element?(node) && node.content.empty?
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def html_with_duplicates_removed_from_the_bottom_up
         
     | 
| 
      
 48 
     | 
    
         
            +
                  all_elements.reverse.delete_if{ |e| all_elements_less_current_element(e).include?(e) }.reverse.compact.join('')
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def all_elements_less_current_element(element)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  remove = true
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  all_elements_less_current_node = all_elements.delete_if do |e|
         
     | 
| 
      
 55 
     | 
    
         
            +
                    if e == element && remove
         
     | 
| 
      
 56 
     | 
    
         
            +
                      remove = false
         
     | 
| 
      
 57 
     | 
    
         
            +
                      true
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                def all_elements
         
     | 
| 
      
 63 
     | 
    
         
            +
                  @all_elements ||= self.fragment.children.map(&:to_html)
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CrazyHarry
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Redact
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                class InvalidStripMethod < StandardError; end;
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                STRIP_METHODS =  %w(strip prune escape whitewash)
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                attr_accessor :attributes, :tags, :unsafe
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def strip!
         
     | 
| 
      
 11 
     | 
    
         
            +
                  fragment.to_text
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def redact!(opts = {})
         
     | 
| 
      
 15 
     | 
    
         
            +
                  self.unsafe       = opts.delete(:unsafe) || opts == {}
         
     | 
| 
      
 16 
     | 
    
         
            +
                  self.tags         = [opts.delete(:tags)].compact.flatten
         
     | 
| 
      
 17 
     | 
    
         
            +
                  self.attributes   = opts.delete(:attributes)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  self.text         = opts.delete(:text)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  self.scope        = opts.delete(:scope)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  prune             = opts.delete(:prune)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  self.steps << strip_unsafe  if self.unsafe
         
     | 
| 
      
 23 
     | 
    
         
            +
                  self.steps << strip_tags    unless prune || self.tags == []
         
     | 
| 
      
 24 
     | 
    
         
            +
                  self.steps << prune_tags    if prune
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  run!
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  self
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                private
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def redact_this_node?(node)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  ( self.text       ? node.text == self.text                          : true ) &&
         
     | 
| 
      
 35 
     | 
    
         
            +
                  ( self.scope      ? node.parent.name == self.scope                  : true ) &&
         
     | 
| 
      
 36 
     | 
    
         
            +
                  ( self.attributes ? self.attributes.any?{ |a,v| node[a.to_s] == v } : true ) &&
         
     | 
| 
      
 37 
     | 
    
         
            +
                  self.tags.include?(node.name)
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def strip_unsafe
         
     | 
| 
      
 41 
     | 
    
         
            +
                  fail InvalidStripMethod, "vaild methods are #{STRIP_METHODS.join(', ')}." unless valid_strip_method?
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  STRIP_METHODS.include?(self.unsafe.to_s) ? self.unsafe.to_sym : :prune
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def valid_strip_method?
         
     | 
| 
      
 47 
     | 
    
         
            +
                  return true if self.unsafe == true || STRIP_METHODS.include?(self.unsafe.to_s)
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def strip_tags
         
     | 
| 
      
 51 
     | 
    
         
            +
                  Loofah::Scrubber.new do |node|
         
     | 
| 
      
 52 
     | 
    
         
            +
                    content = block_node?(node) ? "#{node.content}\n" : "#{node.content} "
         
     | 
| 
      
 53 
     | 
    
         
            +
                    node.replace(content) if redact_this_node?(node)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def block_node?(node)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  Loofah::Elements::BLOCK_LEVEL.include?(node.name)
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                # TODO: Refactor and DRY out--nearly identical to
         
     | 
| 
      
 62 
     | 
    
         
            +
                # ::Default#scrub_tag
         
     | 
| 
      
 63 
     | 
    
         
            +
                def prune_tags
         
     | 
| 
      
 64 
     | 
    
         
            +
                  Loofah::Scrubber.new do |node|
         
     | 
| 
      
 65 
     | 
    
         
            +
                    if redact_this_node?(node)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      node.remove
         
     | 
| 
      
 67 
     | 
    
         
            +
                      Loofah::Scrubber::STOP # don't bother with the rest of the subtree
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
                
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,56 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CrazyHarry
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Translate
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                attr_accessor :add_attributes, :from_text, :to_text
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def translate!(opts = {})
         
     | 
| 
      
 7 
     | 
    
         
            +
                  self.add_attributes   = opts.delete(:add_attributes)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  self.from_text        = opts.delete(:from_text)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  self.to_text          = opts.delete(:to_text)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  self.text             = opts.delete(:text)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  self.scope            = opts.delete(:scope)
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  self.steps << change_attributes if self.add_attributes
         
     | 
| 
      
 14 
     | 
    
         
            +
                  self.steps << change_text if change_text?
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  run!
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  self
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                private
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def translate_this_node?(node)
         
     | 
| 
      
 24 
     | 
    
         
            +
                 ( self.text       ? node.text == self.text                          : true ) &&
         
     | 
| 
      
 25 
     | 
    
         
            +
                 ( self.scope      ? node.parent.name == self.scope                  : true )
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def change_text?
         
     | 
| 
      
 29 
     | 
    
         
            +
                  self.from_text && self.to_text
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                # TODO move this to CrazyHarry::Change.
         
     | 
| 
      
 33 
     | 
    
         
            +
                def change_attributes
         
     | 
| 
      
 34 
     | 
    
         
            +
                  Loofah::Scrubber.new do |node|
         
     | 
| 
      
 35 
     | 
    
         
            +
                    if translate_this_node?(node)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      self.add_attributes.map do |k,v|
         
     | 
| 
      
 37 
     | 
    
         
            +
                        node_key = k.to_s
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                        node[node_key] = [node[node_key], v].compact.join(' ') unless node[node_key].to_s[/#{v}/]
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def change_text
         
     | 
| 
      
 46 
     | 
    
         
            +
                  Loofah::Scrubber.new do |node|
         
     | 
| 
      
 47 
     | 
    
         
            +
                    capitalized_from = self.from_text.capitalize
         
     | 
| 
      
 48 
     | 
    
         
            +
                    capitalized_to   = self.to_text.capitalize
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    node.content = node.content.gsub(/#{self.from_text.downcase}/, self.to_text.downcase) if node.content[/#{self.from_text.downcase}/]
         
     | 
| 
      
 51 
     | 
    
         
            +
                    node.content = node.content.gsub(/#{capitalized_from}/, capitalized_to) if node.content[/#{capitalized_from}/]
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
            end
         
     | 
    
        data/rvmrc.example
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            rvm use 1.9.3@crazy_harry --create
         
     | 
| 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <p>
         
     | 
| 
      
 2 
     | 
    
         
            +
            <b>Location. </b> 
         
     | 
| 
      
 3 
     | 
    
         
            +
            <br />
         
     | 
| 
      
 4 
     | 
    
         
            +
            Golden Nugget formerly Trump Marina is located in Atlantic City, close to Atlantic City Aquarium, Steel Pier, and Atlantic City Hall. Nearby points of interest also include Atlantic City Public Library and Absecon Lighthouse. 
         
     | 
| 
      
 5 
     | 
    
         
            +
            </p>
         
     | 
| 
      
 6 
     | 
    
         
            +
            <p>
         
     | 
| 
      
 7 
     | 
    
         
            +
            <b>Resort Features. </b>
         
     | 
| 
      
 8 
     | 
    
         
            +
            <br />
         
     | 
| 
      
 9 
     | 
    
         
            +
            Dining options at Golden Nugget formerly Trump Marina include 8 restaurants. 4 bars/lounges, a beach bar, and a poolside bar are open for drinks. Room service is available 24 hours a day. Recreational amenities include a children's pool and a health club. The property's full service health spa has massage/treatment rooms and beauty services. This 3 star property has a business center and offers small meeting rooms and audio visual equipment. Wireless and wired high speed Internet access is available in public areas (surcharges apply)..
         
     | 
| 
      
 10 
     | 
    
         
            +
            </p>
         
     | 
| 
      
 11 
     | 
    
         
            +
            <p>
         
     | 
| 
      
 12 
     | 
    
         
            +
            <b>Guestrooms. </b> 
         
     | 
| 
      
 13 
     | 
    
         
            +
            <br /> 
         
     | 
| 
      
 14 
     | 
    
         
            +
            728 air conditioned guestrooms at Golden Nugget formerly Trump Marina feature coffee/tea makers and blackout drapes/curtains. Bathrooms feature complimentary toiletries and hair dryers. Wired high speed Internet access is available for a surcharge. Televisions have pay movies. Also included are irons/ironing boards and clock radios. Guests may request a turndown service and wake up calls. Housekeeping is available daily. 
         
     | 
| 
      
 15 
     | 
    
         
            +
            </p>
         
     | 
| 
      
 16 
     | 
    
         
            +
            <br /><br /> 
         
     | 
| 
      
 17 
     | 
    
         
            +
            <p><strong>Notifications and Fees:</strong>
         
     | 
| 
      
 18 
     | 
    
         
            +
            <br />
         
     | 
| 
      
 19 
     | 
    
         
            +
            </p>
         
     | 
| 
      
 20 
     | 
    
         
            +
            <p></p>
         
     | 
| 
      
 21 
     | 
    
         
            +
            <p></p>
         
     | 
| 
      
 22 
     | 
    
         
            +
            <p></p>
         
     | 
| 
      
 23 
     | 
    
         
            +
            <p>The following fees and deposits are charged by the property at time of service, check in, or check out.  
         
     | 
| 
      
 24 
     | 
    
         
            +
            <ul>
         
     | 
| 
      
 25 
     | 
    
         
            +
              <li>Self parking fee: USD 5 per stay</li>
         
     | 
| 
      
 26 
     | 
    
         
            +
              <li>Valet parking fee: USD 10 per stay</li>
         
     | 
| 
      
 27 
     | 
    
         
            +
              <li>Fee for in room high speed Internet (wired): USD 12.99 (for 24 hours, rates may vary)</li>
         
     | 
| 
      
 28 
     | 
    
         
            +
              <li>Rollaway bed fee: USD 25. per stay</li>
         
     | 
| 
      
 29 
     | 
    
         
            +
            </ul>
         
     | 
| 
      
 30 
     | 
    
         
            +
            </p>
         
     | 
| 
      
 31 
     | 
    
         
            +
            <p>
         
     | 
| 
      
 32 
     | 
    
         
            +
            The above list may not be comprehensive. Fees and deposits may not include tax and are subject to change.
         
     | 
| 
      
 33 
     | 
    
         
            +
            </p> 
         
     | 
| 
      
 34 
     | 
    
         
            +
            <br /><br /> 
         
     | 
| 
      
 35 
     | 
    
         
            +
            <p>
         
     | 
| 
      
 36 
     | 
    
         
            +
            <strong>Notifications and Fees:</strong>
         
     | 
| 
      
 37 
     | 
    
         
            +
            <br />
         
     | 
| 
      
 38 
     | 
    
         
            +
            </p>
         
     | 
| 
      
 39 
     | 
    
         
            +
            <p></p>
         
     | 
| 
      
 40 
     | 
    
         
            +
            <p></p>
         
     | 
| 
      
 41 
     | 
    
         
            +
            <p></p>
         
     | 
| 
      
 42 
     | 
    
         
            +
            <p>The following fees and deposits are charged by the property at time of service, check in, or check out.  
         
     | 
| 
      
 43 
     | 
    
         
            +
            <ul>
         
     | 
| 
      
 44 
     | 
    
         
            +
              <li>Self parking fee: USD 5 per stay</li>
         
     | 
| 
      
 45 
     | 
    
         
            +
              <li>Valet parking fee: USD 10 per stay</li>
         
     | 
| 
      
 46 
     | 
    
         
            +
              <li>Fee for in room high speed Internet (wired): USD 12.99 (for 24 hours, rates may vary)</li>
         
     | 
| 
      
 47 
     | 
    
         
            +
              <li>Rollaway bed fee: USD 25. per stay</li>
         
     | 
| 
      
 48 
     | 
    
         
            +
            </ul>
         
     | 
| 
      
 49 
     | 
    
         
            +
            </p>
         
     | 
| 
      
 50 
     | 
    
         
            +
            <p>The above list may not be comprehensive. Fees and deposits may not include tax and are subject to change. </p>
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <p>
         
     | 
| 
      
 2 
     | 
    
         
            +
            <h3>Location. </h3> 
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Golden Nugget formerly Trump Marina is located in Atlantic City, close to Atlantic City Aquarium, Steel Pier, and Atlantic City Hall. Nearby points of interest also include Atlantic City Public Library and Absecon Lighthouse. 
         
     | 
| 
      
 5 
     | 
    
         
            +
            </p>
         
     | 
| 
      
 6 
     | 
    
         
            +
            <p>
         
     | 
| 
      
 7 
     | 
    
         
            +
            <h3>Resort Features. </h3>
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Dining options at Golden Nugget formerly Trump Marina include 8 restaurants. 4 bars/lounges, a beach bar, and a poolside bar are open for drinks. Room service is available 24 hours a day. Recreational amenities include a children's pool and a health club. The property's full service health spa has massage/treatment rooms and beauty services. This 3 star property has a business center and offers small meeting rooms and audio visual equipment. Wireless and wired high speed Internet access is available in public areas (surcharges apply)..
         
     | 
| 
      
 10 
     | 
    
         
            +
            </p><p>
         
     | 
| 
      
 11 
     | 
    
         
            +
            <h3>Guestrooms. </h3> 
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            728 air conditioned guestrooms at Golden Nugget formerly Trump Marina feature coffee/tea makers and blackout drapes/curtains. Bathrooms feature complimentary toiletries and hair dryers. Wired high speed Internet access is available for a surcharge. Televisions have pay movies. Also included are irons/ironing boards and clock radios. Guests may request a turndown service and wake up calls. Housekeeping is available daily. 
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            </p><p><h3>Notifications and Fees:</h3>
         
     | 
| 
      
 16 
     | 
    
         
            +
            </p><p>The following fees and deposits are charged by the property at time of service, check in, or check out.
         
     | 
| 
      
 17 
     | 
    
         
            +
            </p><ul>
         
     | 
| 
      
 18 
     | 
    
         
            +
            <li>Self parking fee: USD 5 per stay</li>
         
     | 
| 
      
 19 
     | 
    
         
            +
             <li>Valet parking fee: USD 10 per stay</li>
         
     | 
| 
      
 20 
     | 
    
         
            +
             <li>Fee for in room high speed Internet (wired): USD 12.99 (for 24 hours, rates may vary)</li>
         
     | 
| 
      
 21 
     | 
    
         
            +
             <li>Rollaway bed fee: USD 25. per stay</li>
         
     | 
| 
      
 22 
     | 
    
         
            +
            </ul><p>
         
     | 
| 
      
 23 
     | 
    
         
            +
            The above list may not be comprehensive. Fees and deposits may not include tax and are subject to change.
         
     | 
| 
      
 24 
     | 
    
         
            +
            </p>
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe CrazyHarry do
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              let(:harry) { CrazyHarry }
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              it "should allow method chaining" do
         
     | 
| 
      
 8 
     | 
    
         
            +
                harry.fragment('<script>STEAL COOKIE!</script><em>Place</em><p>Lodging</p><b>Location:</b>')
         
     | 
| 
      
 9 
     | 
    
         
            +
                  .redact!( unsafe: true, tags: 'em' )
         
     | 
| 
      
 10 
     | 
    
         
            +
                  .change!( from: 'b', to: 'h3' )
         
     | 
| 
      
 11 
     | 
    
         
            +
                  .translate!( from_text: 'Lodging', to_text: 'Hotel', add_attributes: { class: 'partner' } )
         
     | 
| 
      
 12 
     | 
    
         
            +
                  .to_s.should == 'Place <p class="partner">Hotel</p><h3 class="partner">Location:</h3>'
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              it "should not care about the chain order" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                harry.fragment('<script>STEAL COOKIE!</script><em>Place</em><p>Lodging</p><b>Location:</b>')
         
     | 
| 
      
 17 
     | 
    
         
            +
                  .translate!( from_text: 'Lodging', to_text: 'Hotel', add_attributes: { class: 'partner' } )
         
     | 
| 
      
 18 
     | 
    
         
            +
                  .redact!( unsafe: true, tags: 'em' )
         
     | 
| 
      
 19 
     | 
    
         
            +
                  .change!( from: 'b', to: 'h3' )
         
     | 
| 
      
 20 
     | 
    
         
            +
                  .to_s.should == 'Place <p class="partner">Hotel</p><h3 class="partner">Location:</h3>'
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,83 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe CrazyHarry::Change do
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              #   Change br to p
         
     | 
| 
      
 6 
     | 
    
         
            +
              #   Change b to h3 where b has text: "location"
         
     | 
| 
      
 7 
     | 
    
         
            +
              #   Change b to em where b inside p
         
     | 
| 
      
 8 
     | 
    
         
            +
              #
         
     | 
| 
      
 9 
     | 
    
         
            +
              #   Add attribute: "partner" to all tags
         
     | 
| 
      
 10 
     | 
    
         
            +
              #
         
     | 
| 
      
 11 
     | 
    
         
            +
              #   Another ADS suggestion.  Not sure it if it needed for the first cut.
         
     | 
| 
      
 12 
     | 
    
         
            +
              #   Transform "lodging" to "hotel"
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              context "change" do
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                let(:harry){ CrazyHarry }
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                it "should be able to change one tag to another" do
         
     | 
| 
      
 19 
     | 
    
         
            +
                  harry.fragment( '<b>Location:</b>' ).change!( from: 'b', to: 'h3' ).to_s.should == '<h3>Location:</h3>'
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                it "should unwrap unnecessary paragraphs" do
         
     | 
| 
      
 23 
     | 
    
         
            +
                  harry.fragment('<p><strong>Header</strong><br /></p>').change!(from: 'strong', to: 'h3').to_s.should == 
         
     | 
| 
      
 24 
     | 
    
         
            +
                    '<h3>Header</h3>'
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                it "should not unwrap paragraphs indiscriminately" do
         
     | 
| 
      
 28 
     | 
    
         
            +
                  harry.fragment('<p><b>Header</b><br />Content</p>').change!(from: 'b', to: 'h3').to_s.should ==
         
     | 
| 
      
 29 
     | 
    
         
            +
                    '<p><h3>Header</h3>Content</p>'
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                context "chaining" do
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                   it "should be able to chain calls" do
         
     | 
| 
      
 35 
     | 
    
         
            +
                    harry.fragment(  '<b>Location:</b><br />Saigon' ).change!( from: 'b', to: 'h3').change!( from: 'br', to: 'p' ).to_s.should ==
         
     | 
| 
      
 36 
     | 
    
         
            +
                      '<h3>Location:</h3><p>Saigon</p>'
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  it "should not care about the order of the chain" do
         
     | 
| 
      
 40 
     | 
    
         
            +
                    harry.fragment(  '<b>Location:</b><br />Saigon' ).change!( from: 'br', to: 'p' ).change!( from: 'b', to: 'h3' ).to_s.should ==
         
     | 
| 
      
 41 
     | 
    
         
            +
                      '<h3>Location:</h3><p>Saigon</p>'
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                it "should be able to change all the tags it finds" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                  harry.fragment( '<b>1</b><b>2</b><b>3</b>' ).change!( from: 'b', to: 'h3' ).to_s.should == '<h3>1</h3><h3>2</h3><h3>3</h3>'
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                it "should be able to change a span tag to a div" do
         
     | 
| 
      
 51 
     | 
    
         
            +
                  harry.fragment( '<span>Hotel Details</span>' ).change!( from: 'span', to: 'div' ).to_s.should == '<div>Hotel Details</div>'
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                it "should not change things that it isn't directed to" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                  harry.fragment( '<h3>Hotel Details</h3>' ).change!( from: 'span', to: 'div' ).to_s.should == '<h3>Hotel Details</h3>'
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                it "shouldn't choke if it gets invalid tags" do
         
     | 
| 
      
 59 
     | 
    
         
            +
                  harry.fragment( '<h3>Hotel Details</h3>' ).change!( from: 'snoogenflozen', to: 'snarglebat' ).to_s.should == '<h3>Hotel Details</h3>'
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                context "targeting and scoping" do
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  it "should change all occurrences" do
         
     | 
| 
      
 65 
     | 
    
         
            +
                   harry.fragment( '<div><b>Hotels</b></div><p><b>Hotels</b></p><b>Tents</b><div><p><b>Campervan</b></p></div>' ).change!( from: 'b', to: 'em').to_s.should ==
         
     | 
| 
      
 66 
     | 
    
         
            +
                      '<div><em>Hotels</em></div><p><em>Hotels</em></p><em>Tents</em><div><p><em>Campervan</em></p></div>'
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  it "should be able to target changes by content" do
         
     | 
| 
      
 70 
     | 
    
         
            +
                    harry.fragment( 'Hot <b>hotels</b> in <b>Saigon</b>' ).change!( from: 'b', to: 'em', text: 'hotels' ).to_s.should ==
         
     | 
| 
      
 71 
     | 
    
         
            +
                      'Hot <em>hotels</em> in <b>Saigon</b>'
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  it "should be able to scope changes to specific blocks" do
         
     | 
| 
      
 75 
     | 
    
         
            +
                    harry.fragment( '<div><b>Hotels</b></div><p><b>Hotels</b></p><b>Tents</b>' ).change!( from: 'b', to: 'em', scope: 'p' ).to_s.should ==
         
     | 
| 
      
 76 
     | 
    
         
            +
                      '<div><b>Hotels</b></div><p><em>Hotels</em></p><b>Tents</b>'
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
         
     | 
| 
      
 83 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,86 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe CrazyHarry do
         
     | 
| 
      
 4 
     | 
    
         
            +
              TAGS_TO_REMOVE = {
         
     | 
| 
      
 5 
     | 
    
         
            +
                  paragraph:  '<p></p>',
         
     | 
| 
      
 6 
     | 
    
         
            +
                  ul:         '<ul></ul>',
         
     | 
| 
      
 7 
     | 
    
         
            +
                  div:        '<div></div>'
         
     | 
| 
      
 8 
     | 
    
         
            +
                }
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              let(:harry) { CrazyHarry }
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              context "default actions" do
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                it "should relentlessly remove br tags" do
         
     | 
| 
      
 15 
     | 
    
         
            +
                  harry.fragment('<p>hello</p><br /><strong>HELLO</strong><br /><br />').to_s.should == '<p>hello</p><strong>HELLO</strong>'
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                context "removing blank tags" do
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  TAGS_TO_REMOVE.each do |name,example|
         
     | 
| 
      
 21 
     | 
    
         
            +
                    it "should automatically remove blank #{name} tags" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                      harry.fragment("#{example}<p>Hello!</p>").to_s.should == '<p>Hello!</p>'
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                context "inline tags to blocks" do
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  it "should automatically change br to p" do
         
     | 
| 
      
 31 
     | 
    
         
            +
                    harry.fragment( 'Hotel Details<br />' ).to_s.should == '<p>Hotel Details</p>'
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  it "should automatically change multiple br tags to a single p" do
         
     | 
| 
      
 35 
     | 
    
         
            +
                    harry.fragment(  'Hotel Details<br /><br /><br />' ).to_s.should == '<p>Hotel Details</p>'
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  it "should automatically clear whitespace when converting line-style to block-style" do
         
     | 
| 
      
 39 
     | 
    
         
            +
                     harry.fragment(  'hotel<br />        hostel      <br />').to_s.should == '<p>hotel</p><p>hostel</p>'
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  it "should automatically change all br tags to wrapped p tags" do
         
     | 
| 
      
 43 
     | 
    
         
            +
                    harry.fragment( 'hotel<br /> hostel<br /> tent<br />').to_s.should == '<p>hotel</p><p>hostel</p><p>tent</p>'
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  it "should automatically change all multiple br tags to wrapped tags" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                    harry.fragment(  'hotel<br /><br /><br/> hostel<br /> tent<br />').to_s.should == '<p>hotel</p><p>hostel</p><p>tent</p>'
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  it "should automatically change leading inline tags to block tags" do
         
     | 
| 
      
 51 
     | 
    
         
            +
                    harry.fragment(  '<br /><br />hotel').to_s.should == '<p>hotel</p>'
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  it "should ignore stray inline tags if they don't appear relevant to the context" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                    harry.fragment(  '<br /><br />hotel <br />hostel<br />').to_s.should == '<p>hotel</p><p>hostel</p>'
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                context "de-duping" do
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  it "should automatically de-dupe lists" do
         
     | 
| 
      
 63 
     | 
    
         
            +
                    harry.fragment('<ul><li>Duplicate.</li></ul><ul><li>Duplicate.</li></ul>').to_s.should == '<ul><li>Duplicate.</li></ul>'
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  it "should automatically de-dupe paragraphs" do
         
     | 
| 
      
 67 
     | 
    
         
            +
                    harry.fragment('<p>Lorem Ipsum</p><p>Lorem Ipsum</p>').to_s.should == '<p>Lorem Ipsum</p>'
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  it "should not remove duplicate content that exsists at a different markup level" do
         
     | 
| 
      
 71 
     | 
    
         
            +
                    harry.fragment('<p><strong>Location:</strong></p><strong>Location:</strong>').to_s.should == '<p><strong>Location:</strong></p><strong>Location:</strong>'
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  it "should not alter other content when it de-dupes" do
         
     | 
| 
      
 75 
     | 
    
         
            +
                    harry.fragment('<h3>Here</h3><p>Yep, here.</p><h3>Here</h3><p>Here again.</p>').to_s.should == '<h3>Here</h3><p>Yep, here.</p><p>Here again.</p>'
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  it "should de-dupe if the only content difference is whitespace" do
         
     | 
| 
      
 79 
     | 
    
         
            +
                    pending "Too complicated for the first cut."
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
              end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,122 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe CrazyHarry::Redact do
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              #   Strip all tags  -- should convert </p> and <br> to linebreaks by default
         
     | 
| 
      
 6 
     | 
    
         
            +
              #   Strip tags from text: "HostelWorld"
         
     | 
| 
      
 7 
     | 
    
         
            +
              #   Strip tags from text: "HostelWorld" inside h3
         
     | 
| 
      
 8 
     | 
    
         
            +
              #
         
     | 
| 
      
 9 
     | 
    
         
            +
              #   ADS suggested ability to remove tag and content, so 'kill'  Probably
         
     | 
| 
      
 10 
     | 
    
         
            +
              #   more appropriate for script and image tags
         
     | 
| 
      
 11 
     | 
    
         
            +
              #
         
     | 
| 
      
 12 
     | 
    
         
            +
              #   Kill a where a has attribute: "nofollow", text: "visit Disneyland"
         
     | 
| 
      
 13 
     | 
    
         
            +
              #   Kill img
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              let(:harry){ CrazyHarry }
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              context "strip all tags" do 
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                it "should be able to strip all tags" do
         
     | 
| 
      
 20 
     | 
    
         
            +
                  harry.fragment( "<b>a</b>b<br /><h3>c</h3><img src='blah.jpg' />" ).strip!.should == "a\nb\n\nc\n"
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              context "strip specific tags" do
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                it "should be able to strip unsafe tags" do
         
     | 
| 
      
 28 
     | 
    
         
            +
                  harry.fragment( 'Me steal <script>Cookie!</script>').redact!( unsafe: true ).to_s.should == 'Me steal'
         
     | 
| 
      
 29 
     | 
    
         
            +
                  harry.fragment( 'What is that <bloog>thing</bloog>?').redact!( unsafe: true ).to_s.should == 'What is that ?'
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                it "should allow the unsafe strip method to be overridden (it prunes by default)" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                  fragment = 'Me steal <script>Cookie!</script>'
         
     | 
| 
      
 34 
     | 
    
         
            +
                  harry.fragment( fragment).redact!( unsafe: :escape ).to_s.should == 'Me steal <script>Cookie!</script>'
         
     | 
| 
      
 35 
     | 
    
         
            +
                  harry.fragment( fragment).redact!( unsafe: :strip ).to_s.should == 'Me steal Cookie!'
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                it "should prune unsafe tags if called without any arguments" do
         
     | 
| 
      
 39 
     | 
    
         
            +
                  harry.fragment( 'Me steal <script>Cookie!</script>').redact!.to_s.should == 'Me steal'
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                it "should raise an error if asked for an unknown strip method" do
         
     | 
| 
      
 43 
     | 
    
         
            +
                  -> { harry.fragment( 'Any old thing').redact!( unsafe: 'magical_magic' ).to_s }.should raise_error(CrazyHarry::Redact::InvalidStripMethod)
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                it "should be able to strip a specific tag" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                  harry.fragment( '<b>Location:</b><p>Saigon</p>' ).redact!( tags: 'b' ).to_s.should == "Location: <p>Saigon</p>"
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                it "should strip every occurrence of a tag" do
         
     | 
| 
      
 51 
     | 
    
         
            +
                  harry.fragment( '<b>Location:</b><p>Saigon</p><b>Rates:</b>' ).redact!( tags: 'b' ).to_s.should == "Location: <p>Saigon</p>Rates:"
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                it "should be able to strip multiple tags" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                  harry.fragment( '<b>One</b><p>Saigon <em>Plaza</em></p>').redact!( tags: %w(b em)).to_s.should == "One <p>Saigon Plaza </p>"
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                it "should close a paragraph tag early if the fragment has an illegally nested header tag" do
         
     | 
| 
      
 59 
     | 
    
         
            +
                  harry.fragment( '<b>One</b><p>Saigon <h3>Plaza</h3></p>').redact!( tags: %w(b h3)).to_s.should == "One <p>Saigon </p>Plaza"
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                context "chaining and multiple arguments" do
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  it "should be able to chain calls" do
         
     | 
| 
      
 65 
     | 
    
         
            +
                    harry.fragment( '<b>Location:</b><script>Steal Cookie</script><em>Plaza</em>' ).redact!( tags: 'b' ).redact!( unsafe: true ).to_s.should ==
         
     | 
| 
      
 66 
     | 
    
         
            +
                      'Location: <em>Plaza</em>'
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  it "should accept multiple, different commands in a single call" do
         
     | 
| 
      
 70 
     | 
    
         
            +
                    harry.fragment( '<b>Location:</b><script>Steal Cookie</script><em>Plaza</em>' ).redact!( tags: 'b', unsafe: true ).to_s.should ==
         
     | 
| 
      
 71 
     | 
    
         
            +
                      'Location: <em>Plaza</em>'
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                context "whitespace and breaks" do
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  it "shouldn't add excessive extra whitespace" do
         
     | 
| 
      
 79 
     | 
    
         
            +
                    harry.fragment( '<b>Location: </b> <b>Prices:</b>' ).redact!( tags: 'b' ).to_s.should == 'Location: Prices:'
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  it "should add a newline after a stripped block element" do
         
     | 
| 
      
 83 
     | 
    
         
            +
                    harry.fragment( '<h3>Location:</h3><p>Lorem ipsum</p>' ).redact!( tags: 'h3' ).to_s.should == "Location:\n<p>Lorem ipsum</p>"
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                context "targeting and scope" do
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  it "should allow strip to be targeted by the tag content" do
         
     | 
| 
      
 91 
     | 
    
         
            +
                    harry.fragment( '<h3>Location:</h3><h3>Ho Chi Minh City</h3>' ).redact!( tags: 'h3', text: 'Location:' ).to_s.should ==
         
     | 
| 
      
 92 
     | 
    
         
            +
                      "Location:\n<h3>Ho Chi Minh City</h3>"
         
     | 
| 
      
 93 
     | 
    
         
            +
                  end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                  it "should allow strip to be targeted by an attribute" do
         
     | 
| 
      
 96 
     | 
    
         
            +
                    harry.fragment( '<h3 class="big">Big</h3><h3 class="red">Red</h3>').redact!( tags: 'h3', attributes: { class: 'red' } ).to_s.should ==
         
     | 
| 
      
 97 
     | 
    
         
            +
                      '<h3 class="big">Big</h3>Red'
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  it "should be able to scope changes to specific blocks" do
         
     | 
| 
      
 101 
     | 
    
         
            +
                    harry.fragment( '<div><b>Hotels</b></div><p><b>Hotels</b></p><b>Tents</b>' ).redact!( tags: 'b', scope: 'p' ).to_s.should ==
         
     | 
| 
      
 102 
     | 
    
         
            +
                      '<div><b>Hotels</b></div><p>Hotels </p><b>Tents</b>'
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                  it "should allow strip to be targeted and scoped" do
         
     | 
| 
      
 106 
     | 
    
         
            +
                    harry.fragment( '<b>Location:</b><p><b>Big</b> <b>Bad</b> Hotel</p>' ).redact!( tags: 'b', scope: 'p', text: 'Big' ).to_s.should ==
         
     | 
| 
      
 107 
     | 
    
         
            +
                      '<b>Location:</b><p>Big <b>Bad</b> Hotel</p>'
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
              end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
              context 'pruning' do
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                it 'should be able to prune a tag, removing the tag and its contents' do
         
     | 
| 
      
 117 
     | 
    
         
            +
                  harry.fragment( 'I do not want <h3>Big</h3> images.').redact!( tags: 'h3', prune: true ).to_s.should == 'I do not want images.'
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
              end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe CrazyHarry::Translate do
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              #   Add attribute: "partner" to all tags
         
     | 
| 
      
 6 
     | 
    
         
            +
              #   Transform "lodging" to "hotel"
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              let(:harry) { CrazyHarry }
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              it "should be able to add an attribute to all tags" do
         
     | 
| 
      
 11 
     | 
    
         
            +
                harry.fragment( '<b>a</b><h3>c</h3>' ).translate!( add_attributes: { class: 'from-partner'} ).to_s.should ==
         
     | 
| 
      
 12 
     | 
    
         
            +
                  '<b class="from-partner">a</b><h3 class="from-partner">c</h3>'
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              it "should be able to add multiple attributes to all tags" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                harry.fragment( '<b>a</b><h3>c</h3>' ).translate!( add_attributes: { class: 'boo', bubba: 'beau' } ).to_s.should ==
         
     | 
| 
      
 17 
     | 
    
         
            +
                  '<b class="boo" bubba="beau">a</b><h3 class="boo" bubba="beau">c</h3>'
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              it "should append information to existing attributes" do
         
     | 
| 
      
 21 
     | 
    
         
            +
                harry.fragment( '<h3 class="red">Lorem</h3>' ).translate!( add_attributes: { class: 'from-partner'} ).to_s.should ==
         
     | 
| 
      
 22 
     | 
    
         
            +
                  '<h3 class="red from-partner">Lorem</h3>'
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              it "should be able to tranlate free text in the fragment, preservering case" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                harry.fragment( '<h3>Lodging</h3> lodging' ).translate!( from_text: 'lodging', to_text: 'hotel' ).to_s.should ==
         
     | 
| 
      
 27 
     | 
    
         
            +
                  '<h3>Hotel</h3> hotel'
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              context "targeting and scope" do
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                it "should only add attributes to targeted content"  do
         
     | 
| 
      
 33 
     | 
    
         
            +
                  harry.fragment( '<h3>Location:</h3><h3>Saigon</h3>' ).translate!( add_attributes: { class: 'partner' }, text: 'Location:' ).to_s.should ==
         
     | 
| 
      
 34 
     | 
    
         
            +
                    '<h3 class="partner">Location:</h3><h3>Saigon</h3>'
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                it "should be able to scope changes to specific blocks" do
         
     | 
| 
      
 38 
     | 
    
         
            +
                  harry.fragment( '<div><b>Hotel</b></div><p><b>Hotel</b></p><b>Tent</b>' ).translate!( add_attributes: { class: 'ugly' }, scope: 'p' ).to_s.should ==
         
     | 
| 
      
 39 
     | 
    
         
            +
                    '<div><b>Hotel</b></div><p><b class="ugly">Hotel</b></p><b>Tent</b>'
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,130 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: crazy_harry
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.3
         
     | 
| 
      
 5 
     | 
    
         
            +
              prerelease: 
         
     | 
| 
      
 6 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 7 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 8 
     | 
    
         
            +
            - TA Tyree
         
     | 
| 
      
 9 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 10 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 11 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2012-06-26 00:00:00.000000000 Z
         
     | 
| 
      
 13 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 14 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 15 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 16 
     | 
    
         
            +
              requirement: &2151932960 !ruby/object:Gem::Requirement
         
     | 
| 
      
 17 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 18 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 19 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 20 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 21 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 22 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 23 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 24 
     | 
    
         
            +
              version_requirements: *2151932960
         
     | 
| 
      
 25 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 26 
     | 
    
         
            +
              name: guard
         
     | 
| 
      
 27 
     | 
    
         
            +
              requirement: &2151930220 !ruby/object:Gem::Requirement
         
     | 
| 
      
 28 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 29 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 30 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 31 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 32 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 33 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 34 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 35 
     | 
    
         
            +
              version_requirements: *2151930220
         
     | 
| 
      
 36 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 37 
     | 
    
         
            +
              name: guard-rspec
         
     | 
| 
      
 38 
     | 
    
         
            +
              requirement: &2151928080 !ruby/object:Gem::Requirement
         
     | 
| 
      
 39 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 40 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 41 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 42 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 43 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 44 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 45 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 46 
     | 
    
         
            +
              version_requirements: *2151928080
         
     | 
| 
      
 47 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 48 
     | 
    
         
            +
              name: simplecov
         
     | 
| 
      
 49 
     | 
    
         
            +
              requirement: &2151940320 !ruby/object:Gem::Requirement
         
     | 
| 
      
 50 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 55 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 56 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 57 
     | 
    
         
            +
              version_requirements: *2151940320
         
     | 
| 
      
 58 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 59 
     | 
    
         
            +
              name: loofah
         
     | 
| 
      
 60 
     | 
    
         
            +
              requirement: &2151939040 !ruby/object:Gem::Requirement
         
     | 
| 
      
 61 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 62 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 63 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 64 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 65 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 66 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 67 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 68 
     | 
    
         
            +
              version_requirements: *2151939040
         
     | 
| 
      
 69 
     | 
    
         
            +
            description: CrazyHarry is a high-level html fragment sanitiser/cleaner based on Loofah.
         
     | 
| 
      
 70 
     | 
    
         
            +
            email:
         
     | 
| 
      
 71 
     | 
    
         
            +
            - todd.tyree@lonelyplanet.co.uk
         
     | 
| 
      
 72 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 73 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 74 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 75 
     | 
    
         
            +
            files:
         
     | 
| 
      
 76 
     | 
    
         
            +
            - .gitignore
         
     | 
| 
      
 77 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 78 
     | 
    
         
            +
            - Guardfile
         
     | 
| 
      
 79 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 80 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 81 
     | 
    
         
            +
            - crazy_harry.gemspec
         
     | 
| 
      
 82 
     | 
    
         
            +
            - lib/crazy_harry.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            - lib/crazy_harry/base.rb
         
     | 
| 
      
 84 
     | 
    
         
            +
            - lib/crazy_harry/change.rb
         
     | 
| 
      
 85 
     | 
    
         
            +
            - lib/crazy_harry/default.rb
         
     | 
| 
      
 86 
     | 
    
         
            +
            - lib/crazy_harry/redact.rb
         
     | 
| 
      
 87 
     | 
    
         
            +
            - lib/crazy_harry/translate.rb
         
     | 
| 
      
 88 
     | 
    
         
            +
            - lib/crazy_harry/version.rb
         
     | 
| 
      
 89 
     | 
    
         
            +
            - rvmrc.example
         
     | 
| 
      
 90 
     | 
    
         
            +
            - spec/fixtures/golden_nugget.html
         
     | 
| 
      
 91 
     | 
    
         
            +
            - spec/fixtures/golden_nugget_corrected.html
         
     | 
| 
      
 92 
     | 
    
         
            +
            - spec/integration/crazy_harry_spec.rb
         
     | 
| 
      
 93 
     | 
    
         
            +
            - spec/lib/change_spec.rb
         
     | 
| 
      
 94 
     | 
    
         
            +
            - spec/lib/crazy_harry_spec.rb
         
     | 
| 
      
 95 
     | 
    
         
            +
            - spec/lib/redact_spec.rb
         
     | 
| 
      
 96 
     | 
    
         
            +
            - spec/lib/translate_spec.rb
         
     | 
| 
      
 97 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     | 
| 
      
 98 
     | 
    
         
            +
            homepage: https://github.com/lonelyplanet/crazy_harry
         
     | 
| 
      
 99 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 100 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 101 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 102 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 103 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 104 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 105 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 106 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 107 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 108 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 109 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 110 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 111 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 112 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 113 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 114 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 115 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 116 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 117 
     | 
    
         
            +
            rubyforge_project: crazy_harry
         
     | 
| 
      
 118 
     | 
    
         
            +
            rubygems_version: 1.8.10
         
     | 
| 
      
 119 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 120 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 121 
     | 
    
         
            +
            summary: A High level HTML fragment sanitizer.
         
     | 
| 
      
 122 
     | 
    
         
            +
            test_files:
         
     | 
| 
      
 123 
     | 
    
         
            +
            - spec/fixtures/golden_nugget.html
         
     | 
| 
      
 124 
     | 
    
         
            +
            - spec/fixtures/golden_nugget_corrected.html
         
     | 
| 
      
 125 
     | 
    
         
            +
            - spec/integration/crazy_harry_spec.rb
         
     | 
| 
      
 126 
     | 
    
         
            +
            - spec/lib/change_spec.rb
         
     | 
| 
      
 127 
     | 
    
         
            +
            - spec/lib/crazy_harry_spec.rb
         
     | 
| 
      
 128 
     | 
    
         
            +
            - spec/lib/redact_spec.rb
         
     | 
| 
      
 129 
     | 
    
         
            +
            - spec/lib/translate_spec.rb
         
     | 
| 
      
 130 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     |