Class: Y::XMLText

Inherits:
Object
  • Object
show all
Defined in:
lib/y/xml.rb

Overview

A XMLText

Someone should not instantiate a text directly, but use Doc#get_xml_text, Y::XMLElement#insert_text, Y::XMLElement#push_text, Y::XMLElement#unshift_text instead.

The XMLText API is similar to Text, but adds a few methods to make it easier to work in structured XML documents.

Examples:

doc = Y::Doc.new
xml_text = doc.get_xml_text("my xml text")

puts xml_text.to_s

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(doc = nil) ⇒ XMLText

Create a new XMLText instance

Parameters:

  • doc (Y::Doc) (defaults to: nil)


489
490
491
492
493
# File 'lib/y/xml.rb', line 489

def initialize(doc = nil)
  @document = doc || Y::Doc.new

  super()
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object (private)

make attributes just work on an element in the form of attr_name and attr_name=

Examples:

Set and get an attribute

doc = Y::Doc.new
xml_element = doc.get_xml_element("my xml")
xml_element.attr_name = "Hello"

puts xml_element.attr_name # "Hello"


739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
# File 'lib/y/xml.rb', line 739

def method_missing(method_name, *args, &block)
  is_setter = method_name.to_s.end_with?("=")

  setter = method_name
  setter += "=" unless is_setter
  getter = method_name
  getter = getter.to_s.slice(0...-1)&.to_sym if is_setter

  define_singleton_method(setter.to_sym) do |new_val|
    document.current_transaction do |tx|
      yxml_text_insert_attribute(tx,
                                 method_name.to_s
                                            .delete_suffix("=")
                                            .delete_prefix("attr_"),
                                 new_val)
    end
  end

  define_singleton_method(getter) do
    document.current_transaction do |tx|
      yxml_text_get_attribute(tx, method_name.to_s.delete_prefix("attr_"))
    end
  end

  if is_setter
    value = args[0]
    send(setter, value)
  end
rescue StandardError
  super(method_name, *args, &block)
end

Instance Attribute Details

#documentY::Doc

Returns The document this array belongs to.

Returns:

  • (Y::Doc)

    The document this array belongs to



484
485
486
# File 'lib/y/xml.rb', line 484

def document
  @document
end

Instance Method Details

#<<(str) ⇒ void Also known as: push

This method returns an undefined value.

Push a string to the end of the text node

Parameters:

  • str (String)


499
500
501
# File 'lib/y/xml.rb', line 499

def <<(str)
  document.current_transaction { |tx| yxml_text_push(tx, str) }
end

#attach(callback = nil, &block) ⇒ Integer

Attach a listener to get notified about changes

Parameters:

  • callback (Proc) (defaults to: nil)

Returns:

  • (Integer)

    subscription_id



509
510
511
512
# File 'lib/y/xml.rb', line 509

def attach(callback = nil, &block)
  yxml_text_observe(callback) unless callback.nil?
  yxml_text_observe(block.to_proc) unless block.nil?
end

#attrsHash

Return text attributes

Returns:

  • (Hash)


517
518
519
# File 'lib/y/xml.rb', line 517

def attrs
  document.current_transaction { |tx| yxml_text_attributes(tx) }
end

#detach(subscription_id) ⇒ void

This method returns an undefined value.

Detach a listener

Parameters:

  • subscription_id (Integer)


525
526
527
# File 'lib/y/xml.rb', line 525

def detach(subscription_id)
  yxml_text_unobserve(subscription_id)
end

#format(index, length, attrs) ⇒ void

This method returns an undefined value.

Format text

Parameters:

  • index (Integer)
  • length (Integer)
  • attrs (Hash)


535
536
537
538
539
# File 'lib/y/xml.rb', line 535

def format(index, length, attrs)
  document.current_transaction do |tx|
    yxml_text_format(tx, index, length, attrs)
  end
end

#insert(index, value, attrs = nil) ⇒ void

This method returns an undefined value.

Insert a value at position and with optional attributes. This method is similar to String#insert, except for the optional third attrs argument.

The value can be any of the supported types:

  • Boolean
  • String
  • Numeric
  • Array (where element types must be supported)
  • Hash (where the the types of key and values must be supported)

Examples:

Insert a string at position

doc = Y::Doc.new
text = doc.get_text("my text")
text << "Hello, "

text.insert(7, "World!")

puts text.to_s == "Hello, World!" # true

Parameters:

  • index (Integer)
  • value (String, Float, Integer, Array, Hash, Boolean)
  • attrs (Hash, nil) (defaults to: nil)


567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
# File 'lib/y/xml.rb', line 567

def insert(index, value, attrs = nil)
  document.current_transaction do |tx|
    if value.is_a?(String)
      yxml_text_insert(tx, index, value) if attrs.nil?
      unless attrs.nil?
        yxml_text_insert_with_attrs(tx, index, value,
                                    attrs)
      end

      return nil
    end

    if can_insert?(value)
      yxml_text_insert_embed(tx, index, value) if attrs.nil?
      unless attrs.nil?
        yxml_text_insert_embed_with_attrs(tx, index, value,
                                          attrs)
      end

      return nil
    end

    raise ArgumentError,
          "Can't insert value. `#{value.class.name}` isn't supported."
  end
end

#lengthvoid Also known as: size

This method returns an undefined value.

Return length of string



599
600
601
# File 'lib/y/xml.rb', line 599

def length
  document.current_transaction { |tx| yxml_text_length(tx) }
end

#next_siblingY::XMLElement, ...

Return adjacent XMLElement or XMLText node (next)

Returns:



608
609
610
611
612
# File 'lib/y/xml.rb', line 608

def next_sibling
  node = document.current_transaction { |tx| yxml_text_next_sibling(tx) }
  node.document = document
  node
end

#parentY::XMLElement?

Return parent XMLElement

Returns:



617
618
619
620
621
# File 'lib/y/xml.rb', line 617

def parent
  node = yxml_text_parent
  node.document = document
  node
end

#prev_siblingY::XMLElement, ...

Return adjacent XMLElement or XMLText node (prev)

Returns:



626
627
628
629
630
# File 'lib/y/xml.rb', line 626

def prev_sibling
  node = document.current_transaction { |tx| yxml_text_prev_sibling(tx) }
  node&.document = document
  node
end

#slice!(index) ⇒ void #slice!(start, length) ⇒ void #slice!(range) ⇒ void

This method returns an undefined value.

Removes a part from text

Attention: In comparison to String#slice, #slice! will not return the substring that gets removed. Even this being technically possible, it requires us to read the substring before removing it, which is not desirable in most situations.

Examples:

Removes a single character

doc = Y::Doc.new

text = doc.get_xml_text("my xml text")
text << "Hello"

text.slice!(0)

text.to_s == "ello" # true

Removes a range of characters

doc = Y::Doc.new

text = doc.get_xml_text("my xml text")
text << "Hello"

text.slice!(1..2)
text.to_s == "Hlo" # true

text.slice!(1...2)
text.to_s == "Ho" # true

Removes a range of chars from start and for given length

doc = Y::Doc.new

text = doc.get_xml_text("my xml text")
text << "Hello"

text.slice!(0, 3)

text.to_s == "lo" # true

Overloads:

  • #slice!(index) ⇒ void

    Removes a single character at index

  • #slice!(start, length) ⇒ void

    Removes a range of characters

  • #slice!(range) ⇒ void

    Removes a range of characters



683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
# File 'lib/y/xml.rb', line 683

def slice!(*args)
  document.current_transaction do |tx|
    if args.empty?
      raise ArgumentError,
            "Provide one of `index`, `range`, `start, length` as arguments"
    end

    if args.size == 1
      arg = args.first

      if arg.is_a?(Range)
        yxml_text_remove_range(tx, arg.first, arg.last - arg.first)
        return nil
      end

      if arg.is_a?(Numeric)
        yxml_text_remove_range(tx, arg.to_int, 1)
        return nil
      end
    end

    if args.size == 2
      first, second = args

      if first.is_a?(Numeric) && second.is_a?(Numeric)
        yxml_text_remove_range(tx, first, second)
        return nil
      end
    end

    raise ArgumentError, "Please check your arguments, can't slice."
  end
end

#to_sString

Returns string representation of XMLText

Returns:

  • (String)


722
723
724
# File 'lib/y/xml.rb', line 722

def to_s
  document.current_transaction { |tx| yxml_text_to_s(tx) }
end