Class: Microformats::BasicNestedFormat

Inherits:
Object
  • Object
show all
Defined in:
lib/uformats/basic.rb

Direct Known Subclasses

HCalendar::Event, HCard, HReview

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, url = nil) ⇒ BasicNestedFormat

class << self



85
86
87
88
89
90
91
92
93
94
# File 'lib/uformats/basic.rb', line 85

def initialize(source, url=nil)
  if source.respond_to?(:each_element)
    @source = source
  else
    @source = REXML::Document.new(source.to_s)
  end
  @url = url
  @tree = parse(__class__.structure, @source, MethodHash.new)
  post_process!
end

Instance Attribute Details

#sourceObject (readonly)

Returns the value of attribute source.



95
96
97
# File 'lib/uformats/basic.rb', line 95

def source
  @source
end

Class Method Details

.each(source, url = nil) ⇒ Object

Yields a new instance for each of the matching microformats within the given document.



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/uformats/basic.rb', line 61

def each(source, url=nil)
  if source.respond_to?(:each_element)
    xml_source = source
  else
    xml_source = REXML::Document.new(source.to_s)
  end
  Microformats.expand_include_patterns!(xml_source)
  Microformats.each_element_by_class(xml_source, identifier) do |element|
    yield new(element.dup, url)
  end
end

.first(source, url = nil) ⇒ Object

Returns a new instance for the first matching microformat in the given document.



77
78
79
80
81
# File 'lib/uformats/basic.rb', line 77

def first(source, url=nil)
  each(source, url) do |mf|
    return mf
  end
end

.identifier(ident = nil) ⇒ Object

By default, the name of the class is converted to lowercase and used as the CSS class identifying this format (e.g. HReview => “hreview”). This method can be used to override this.



52
53
54
55
# File 'lib/uformats/basic.rb', line 52

def identifier(ident=nil)
  @identifier_class = ident if ident
  return @identifier_class ||= self.to_s.split('::').last.downcase.to_sym
end

.structure(structure = nil) ⇒ Object

Define or return a hash describing the structure of the derived microformat, using symbols, hashes, and arrays.

E.g.

structure({
  :foo => :integer,   # singular integral value
  :bar => [:string],  # singular or plural string value
  :baz => {           # substructure below 'baz'
    :created_on => :datetime # 'created-on' is interpeted as a date/time value
  }
})


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/uformats/basic.rb', line 30

def structure(structure=nil)
  if structure
    @structure = structure
    legal_keys = []
    structure.each do |key, value|
      legal_keys << key
      if value.is_a?(Array)
        legal_keys << Pluralizer.pluralize(key)
      end
    end
    legal_keys.each do |key|
      class_eval "def #{key}() return Pluralizer.singularized_lookup(@tree, :#{key}) ; end"
    end
  end
  return @structure
end

Instance Method Details

#absolute_url(relative_url) ⇒ Object



239
240
241
242
# File 'lib/uformats/basic.rb', line 239

def absolute_url(relative_url)
  return relative_url unless @url
  return URI.join(@url, relative_url).to_s
end

#lookup(*list) ⇒ Object

Instead of worrying about calling methods on nil, lookup provides an easy way of accessing deeply nested data.

E.g.

object.somethings[1].other # => error if somethings[1] is nil
object.lookup(:somethings, 1, :other) # => nil if any level is nil


253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/uformats/basic.rb', line 253

def lookup(*list)
  tree = @tree
  list.each do |level|
    if level.is_a?(Symbol)
      tree = tree.__send__(level)
    else
      tree = tree.__send__(:[], level)
    end
    return nil unless tree
  end
  return tree
end

#parse(structure, source, default_tree = nil) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/uformats/basic.rb', line 100

def parse(structure, source, default_tree=nil)
  tree = default_tree || MethodHash.new
  structure.each do |tag, substructure|
    if substructure.is_a?(Array)
      key = Pluralizer.pluralize(tag)
    else
      key = tag
    end
    Microformats.each_element_by_class(source, tag) do |element|
      tree[key] = parse_tag(substructure, source, tag)
    end
  end
  return tree
end

#parse_tag(substructure, source, tag) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/uformats/basic.rb', line 115

def parse_tag(substructure, source, tag)
  if substructure.is_a? Array
    substructure = substructure[0]
    elements = []
    is_plural = true
  else
    is_plural = false
  end
  Microformats.each_element_by_class(source, tag) do |element|
    if substructure.is_a? Hash
      this = parse(substructure, element)
      # Special case for values that can be encapsulated or not
      unless this[:value]
        ignored_classes = substructure.keys - [:value]
        if substructure[:value] == :value
          v = process_as_value(element, ignored_classes)
          this[:value] ||= v if v
        elsif substructure[:value] == :email
          v = process_value_as_email(element)
          this[:value] ||= v if v
        end
      end
    else
      this = self.__send__("process_as_#{substructure}".to_sym, element)
    end
    if is_plural
      elements << this
    else
      return this
    end
  end
  return elements
end

#post_process!Object



97
98
# File 'lib/uformats/basic.rb', line 97

def post_process!
end

#process_as_datetime(element) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/uformats/basic.rb', line 190

def process_as_datetime(element)
  text = process_as_string(element)
  return nil unless text && text =~ /\d{2,}/
  text << '-01T00:00:00Z' if text =~ /^\d{4}-\d{2}$/
  text << '01T000000Z' if text =~ /^\d{6}$/
  text << '-T00:00:00Z' if text =~ /^\d{4}-\d{2}-\d{2}$/
  text << 'T000000Z' if text =~ /^\d{8}$/
  text.gsub!(/\++/, '+')
  text.gsub!(/\-+/, '-')
  begin
    return Time.parse(text)
  rescue
    return nil
  end
end

#process_as_email(element) ⇒ Object



224
225
226
227
228
229
230
231
# File 'lib/uformats/basic.rb', line 224

def process_as_email(element)
  url = process_as_url(element)
  if url
    return url.sub(/^mailto:/, '')
  else
    return process_as_string(element)
  end
end

#process_as_float(element) ⇒ Object



179
180
181
182
183
184
# File 'lib/uformats/basic.rb', line 179

def process_as_float(element)
  text = process_as_string(element)
  return nil unless text
  return nil unless text =~ /^\d+(?:\.\d+)?$/
  return text.to_f
end

#process_as_integer(element) ⇒ Object



172
173
174
175
176
177
# File 'lib/uformats/basic.rb', line 172

def process_as_integer(element)
  text = process_as_string(element)
  return nil unless text
  return nil unless text =~ /^\d+$/
  return text.to_i(10)
end

#process_as_string(element, ignored_classes = []) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/uformats/basic.rb', line 149

def process_as_string(element, ignored_classes=[])
  case element.fully_expanded_name
  when 'abbr'
    return element.attribute('title').value.strip
  when 'img'
    return element.attribute('alt').value.strip
  else
    buffer = ''
    element.children.each do |child|
      case child
      when REXML::Text
        buffer << child.to_s
      else
        has_classes = Microformats.classes_for_element(child)
        if (has_classes & ignored_classes).empty?
          buffer << process_as_string(child, ignored_classes)
        end
      end
    end
    return HTMLEntities.decode_entities(buffer.strip.gsub(/\s+/um, ' '))
  end
end

#process_as_url(element) ⇒ Object



206
207
208
209
210
211
212
213
214
215
# File 'lib/uformats/basic.rb', line 206

def process_as_url(element)
  element.each_element('descendant-or-self::*[@href or @src]') do |subelement|
    if (href = subelement.attribute('href'))
      return absolute_url(href.value.strip)
    elsif (src = subelement.attribute('src'))
      return absolute_url(src.value.strip)
    end
  end
  return nil
end

#process_as_value(element, ignored_classes = []) ⇒ Object



217
218
219
220
221
222
# File 'lib/uformats/basic.rb', line 217

def process_as_value(element, ignored_classes=[])
  Microformats.each_element_by_class(element, :value) do |e|
    return process_as_string(e, ignored_classes)
  end
  return process_as_string(element, ignored_classes)
end

#process_as_xhtml(element) ⇒ Object



186
187
188
# File 'lib/uformats/basic.rb', line 186

def process_as_xhtml(element)
  return element.children.map{ |c| c.to_s }.join.strip
end

#process_value_as_email(element) ⇒ Object



233
234
235
236
237
# File 'lib/uformats/basic.rb', line 233

def process_value_as_email(element)
  email = process_as_url(element)
  return email.sub(/^mailto:/, '') if email
  return process_as_value(element)
end