Class: Taggie

Inherits:
String show all
Defined in:
lib/taggie.rb

Constant Summary collapse

AttributeValue =
'("|\')(.*?)\2|(\S*)'
OpenTag =
'<(\w+)[^>]*'
CloseTag =
'\/>|>'
SpecialTags =
'<!--.*?-->|<\?.*?\?>|[^>]'
TagMatcher =
/(#{OpenTag}(?:#{CloseTag}((?:#{OpenTag}(?:#{CloseTag}.*<\/\4>)|#{SpecialTags})*)<\/\2>)|#{SpecialTags}*)/m

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from String

#to_taggie

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *a) ⇒ Object



17
# File 'lib/taggie.rb', line 17

def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.to_s]:super end

Instance Attribute Details

#parentObject

Returns the value of attribute parent.



9
10
11
# File 'lib/taggie.rb', line 9

def parent
  @parent
end

Instance Method Details

#[](a) ⇒ Object



10
# File 'lib/taggie.rb', line 10

def [] a; [Integer,Range].include?(a.class)?super: to_h[a.to_s] end

#[]=(a, v) ⇒ Object



11
# File 'lib/taggie.rb', line 11

def []= a,v;@attributes=@tag=nil;[Integer,Range].include?(a.class)?super: !%w(comment string).include?(type)? v ? (q=v.include?('"')? "'":'"';sub!(/^([^>]+#{a}=)(?:#{AttributeValue})/m,"\\1#{q}#{v}#{q}");sub!(/^([^>]+?)\s*(\/|\?)?>/m, "\\1 #{a}=#{q}#{v}#{q}\\2>") if tag !~/\s+#{a}=/m):sub!(/^([^>]+)\s+#{a}=(?:#{AttributeValue})/,'\1'):nil;rebuild!;v end

#attributesObject



12
# File 'lib/taggie.rb', line 12

def attributes;@attributes||=%w(comment doctype string).include?(type)?[]:tag.scan(/([\S]+)=(?:#{AttributeValue})/m).map!{|m|[m[0],m[2]||m[3]]} end

#childrenObject



13
# File 'lib/taggie.rb', line 13

def children;@children||=inner_html.siblings_and_self.map!{|c|c.parent=self;c} end

#inner_htmlObject



14
# File 'lib/taggie.rb', line 14

def inner_html;r,c=inner_html_regex;m=match(r);m ?m.captures[c]:'' end

#inner_html=(v) ⇒ Object



15
# File 'lib/taggie.rb', line 15

def inner_html= v;@children=nil;sub! inner_html,v;rebuild!;v end

#inner_html_regexObject



16
# File 'lib/taggie.rb', line 16

def inner_html_regex;r,c={'comment'=>/^<!--(.*?)-->/m,'doctype'=>//,'string'=>/^([^<]+)/m,'xml'=>/^<\?(.*?)\?>/m}[type],0;r,c=TagMatcher,2 if r.nil?;[r,c] end

#rebuild!Object



18
# File 'lib/taggie.rb', line 18

def rebuild!;(parent.inner_html=parent.children.join;parent.parent.rebuild! if parent.parent) if parent end

#siblingsObject



19
# File 'lib/taggie.rb', line 19

def siblings;siblings_and_self[1..-1] end

#siblings_and_selfObject



20
# File 'lib/taggie.rb', line 20

def siblings_and_self;@siblings_and_self||=scan(inner_html_regex[0]).map!{|m|m[0]} end

#tagObject



21
# File 'lib/taggie.rb', line 21

def tag;@tag||={'comment'=>self,'string'=>inner_html}[type]||match(/^([^>]+>)/m).captures[0] end

#to_hObject



22
# File 'lib/taggie.rb', line 22

def to_h; Hash[*attributes.flatten].merge! :html=>self end

#to_sObject



23
# File 'lib/taggie.rb', line 23

def to_s; String.new self end

#typeObject



24
# File 'lib/taggie.rb', line 24

def type;@type||(m={(/^<([\w\-_:]+)[^>]*>/m)=>'1',(/^<!--/m)=>'comment',(/^<!doctype[^>]*>/mi)=>'doctype',(/^<\?/m)=>'xml'}.detect{|r,v|r=~self};@type=m ?eval('$'+m[1])||m[1]:'string') end