Class: FeedMe::FeedData
- Inherits:
-
Object
- Object
- FeedMe::FeedData
- Defined in:
- lib/feedme.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#fm_builder ⇒ Object
readonly
Returns the value of attribute fm_builder.
-
#fm_parent ⇒ Object
readonly
Returns the value of attribute fm_parent.
-
#fm_tag_name ⇒ Object
readonly
Returns the value of attribute fm_tag_name.
Instance Method Summary collapse
- #[](key) ⇒ Object
- #[]=(key, value) ⇒ Object
-
#call_virtual_method(sym, args = [], history = []) ⇒ Object
There are several virtual methods for each attribute/tag.
- #delete(key) ⇒ Object
- #each ⇒ Object
- #each_with_index ⇒ Object
-
#id ⇒ Object
special handling for atom id tags, due to conflict with ruby’s Object#id method.
-
#initialize(tag_name, parent, builder) ⇒ FeedData
constructor
A new instance of FeedData.
- #key?(key) ⇒ Boolean
- #keys ⇒ Object
- #method_missing(name, *args) ⇒ Object
- #size ⇒ Object
- #to_indented_s(indent_step = 2) ⇒ Object
- #to_s ⇒ Object
-
#transform(tag, trans) ⇒ Object
Apply transformations to a tag value.
- #transform_value(trans_array, value) ⇒ Object
Constructor Details
#initialize(tag_name, parent, builder) ⇒ FeedData
Returns a new instance of FeedData.
334 335 336 337 338 339 |
# File 'lib/feedme.rb', line 334 def initialize(tag_name, parent, builder) @fm_tag_name = tag_name @fm_parent = parent @fm_builder = builder @data = {} end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args) ⇒ Object
389 390 391 392 393 394 395 396 397 |
# File 'lib/feedme.rb', line 389 def method_missing(name, *args) result = begin call_virtual_method(name, args) rescue NameError raise if fm_builder.[:error_on_missing_key] end result = '' if result.nil? and fm_builder.[:empty_string_for_nil] result end |
Instance Attribute Details
#fm_builder ⇒ Object (readonly)
Returns the value of attribute fm_builder.
332 333 334 |
# File 'lib/feedme.rb', line 332 def fm_builder @fm_builder end |
#fm_parent ⇒ Object (readonly)
Returns the value of attribute fm_parent.
332 333 334 |
# File 'lib/feedme.rb', line 332 def fm_parent @fm_parent end |
#fm_tag_name ⇒ Object (readonly)
Returns the value of attribute fm_tag_name.
332 333 334 |
# File 'lib/feedme.rb', line 332 def fm_tag_name @fm_tag_name end |
Instance Method Details
#[](key) ⇒ Object
365 366 367 |
# File 'lib/feedme.rb', line 365 def [](key) @data[clean_tag(key)] end |
#[]=(key, value) ⇒ Object
369 370 371 |
# File 'lib/feedme.rb', line 369 def []=(key, value) @data[clean_tag(key)] = value end |
#call_virtual_method(sym, args = [], history = []) ⇒ Object
There are several virtual methods for each attribute/tag.
-
Tag/attribute name: since tags/attributes are stored as arrays,
the instance variable name is the tag/attribute name followed by ‘_array’. The tag/attribute name is actually a virtual method that returns the first element in the array. If a Proc is passed as the first argument and the array has more than one element, the Proc is used to sort the array before returning the first element.
-
Aliases: for tags/attributes with aliases, the alias is a virtual
method that simply forwards to the aliased method.
-
Any name that ends with a ‘?’ returns true if the name without
the ‘?’ is a valid method and has a non-nil value.
-
Any name that ends with a ‘!’ returns the value of the name
without the ‘!’, modified by the currently active set of bang mods
-
Tag/attribute name + ‘_value’: returns the content portion of
an element if it has both attributes and content, , or to return the default attribute (defined by the value_tags property). Otherwise equivalent to just the tag/attribute name.
-
Tag/attribute name + ‘_count’: shortcut for tag/attribute
array.size.
-
If the tag name is of the form “tag+rel”, the tag having the
specified rel value is returned
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'lib/feedme.rb', line 420 def call_virtual_method(sym, args=[], history=[]) # make sure we don't get stuck in an infinite loop history.each do |call| if call[0] == fm_tag_name and call[1] == sym raise FeedMe::InfiniteCallLoopError.new(sym, history) end end history << [ fm_tag_name, sym ] name = clean_tag(sym) name_str = name.to_s array_key = arrayize(name.to_s) result = if key? name self[name] elsif key? array_key array = self[array_key] elt = if array.size > 1 if (!args.empty? && args.first.is_a?(Proc)) args.first.call(array) elsif (fm_builder.value_selectors.key?(name)) fm_builder.value_selectors[name].call(array) elsif !fm_builder.default_value_selector.nil? fm_builder.default_value_selector.call(array) end end elt || array.first elsif name_str[-1,1] == '?' !call_virtual_method(name_str[0..-2], args, history).nil? rescue false elsif name_str[-1,1] == '!' value = call_virtual_method(name_str[0..-2], args, history) transform_value(fm_builder.default_transformation, value) elsif name_str =~ /(.+)_values/ call_virtual_method(arrayize($1), args, history).collect do |value| _resolve_value value end elsif name_str =~ /(.+)_value/ _resolve_value call_virtual_method($1, args, history) elsif name_str =~ /(.+)_count/ call_virtual_method(arrayize($1), args, history).size elsif name_str =~ /(.+)_(.+)/ && fm_builder.transformations.key?($2) value = call_virtual_method($1, args, history) transform_value(fm_builder.transformations[$2], value) elsif name_str.include?('/') # this is only intended to be used internally value = self name_str.split('/').each do |p| parts = p.split('_') name = clean_tag(parts[0]) new_args = parts.size > 1 ? parts[1..-1] : args value = (value.method(name).call(*new_args) rescue value.call_virtual_method(name, new_args, history)) rescue nil break if value.nil? end value elsif name_str.include?('+') name_data = name_str.split('+') rel = name_data[1] value = nil call_virtual_method(arrayize(name_data[0]), args, history).each do |elt| next unless elt.is_a?(FeedData) and elt.rel? value = elt if elt.rel.casecmp(rel) == 0 break unless value.nil? end value elsif fm_builder.aliases.key? name names = fm_builder.aliases[name] names = [names] unless names.is_a? Array value = nil names.each do |name| value = (method(name).call(*args) rescue call_virtual_method(name, args, history)) rescue next break unless value.nil? end value else nil end raise NameError.new("No such method '#{name}'", name) if result.nil? result end |
#delete(key) ⇒ Object
349 350 351 |
# File 'lib/feedme.rb', line 349 def delete(key) @data.delete(clean_tag(key)) end |
#each ⇒ Object
353 354 355 |
# File 'lib/feedme.rb', line 353 def each @data.each {|key, value| yield(key, value) } end |
#each_with_index ⇒ Object
357 358 359 |
# File 'lib/feedme.rb', line 357 def each_with_index @data.each_with_index {|key, value, index| yield(key, value, index) } end |
#id ⇒ Object
special handling for atom id tags, due to conflict with ruby’s Object#id method
375 376 377 |
# File 'lib/feedme.rb', line 375 def id key?(:id) ? self[:id] : call_virtual_method(:id) end |
#key?(key) ⇒ Boolean
341 342 343 |
# File 'lib/feedme.rb', line 341 def key?(key) @data.key?(clean_tag(key)) end |
#keys ⇒ Object
345 346 347 |
# File 'lib/feedme.rb', line 345 def keys @data.keys end |
#size ⇒ Object
361 362 363 |
# File 'lib/feedme.rb', line 361 def size @data.size end |
#to_indented_s(indent_step = 2) ⇒ Object
383 384 385 386 387 |
# File 'lib/feedme.rb', line 383 def to_indented_s(indent_step=2) FeedMe.pretty_to_s(self, indent_step, 0, Proc.new do |key, value| (value.is_a?(Array) && value.size == 1) ? [unarrayize(key), value.first] : [key, value] end) end |
#to_s ⇒ Object
379 380 381 |
# File 'lib/feedme.rb', line 379 def to_s to_indented_s end |
#transform(tag, trans) ⇒ Object
Apply transformations to a tag value. Can either accept a transformation name or an array of transformation function names.
505 506 507 508 509 510 |
# File 'lib/feedme.rb', line 505 def transform(tag, trans) value = call_virtual_method(tag) or return nil transformations = trans.is_a?(String) ? fm_builder.transformations[trans] : trans transform_value(transformations, value) end |
#transform_value(trans_array, value) ⇒ Object
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
# File 'lib/feedme.rb', line 512 def transform_value(trans_array, value) trans_array.each do |t| return nil if value.nil? if t.is_a? String value = transform_value(fm_builder.transformations[t], value) else if t.is_a? Symbol t_name = t args = [] elsif t[0].is_a? Array raise 'array where symbol expected' else t_name = t[0] args = t[1..-1] end trans = fm_builder.transformation_fns[t_name] or raise NoMethodError.new("No such transformation #{t_name}", t_name) if value.is_a? Array value = value.collect do |x| x.nil? ? nil : trans.call(x, *args) end.compact else value = trans.call(value, *args) end end end value end |