Class: DICOM::Parent

Inherits:
Object
  • Object
show all
Includes:
Logging
Defined in:
lib/dicom/parent.rb,
lib/dicom/d_read.rb,
lib/dicom/d_write.rb

Overview

Super class which contains common code for all parent elements.

Inheritance

Since all parents inherit from this class, these methods are available to instances of the following classes:

  • DObject

  • Item

  • Sequence

Direct Known Subclasses

ImageItem, Sequence

Instance Method Summary collapse

Methods included from Logging

included, #logger

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args, &block) ⇒ Object

Handles missing methods, which in our case is intended to be dynamic method names matching DICOM elements in the dictionary.

When a dynamic method name is matched against a DICOM element, this method:

  • Returns the element if the method name suggests an element retrieval, and the element exists.

  • Returns nil if the method name suggests an element retrieval, but the element doesn’t exist.

  • Returns a boolean, if the method name suggests a query (?), based on whether the matched element exists or not.

  • When the method name suggests assignment (=), an element is created with the supplied arguments, or if the argument is nil, the element is deleted.

  • When a dynamic method name is not matched against a DICOM element, and the method is not defined by the parent, a NoMethodError is raised.

Parameters:

  • sym (Symbol)

    a method name



530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
# File 'lib/dicom/parent.rb', line 530

def method_missing(sym, *args, &block)
  # Try to match the method against a tag from the dictionary:
  tag = LIBRARY.as_tag(sym.to_s) || LIBRARY.as_tag(sym.to_s[0..-2])
  if tag
    if sym.to_s[-1..-1] == '?'
      # Query:
      return self.exists?(tag)
    elsif sym.to_s[-1..-1] == '='
      # Assignment:
      unless args.length==0 || args[0].nil?
        # What kind of element to create?
        if tag == 'FFFE,E000'
          return self.add_item
        elsif LIBRARY.element(tag).vr == 'SQ'
          return self.add(Sequence.new(tag))
        else
          return self.add(Element.new(tag, *args))
        end
      else
        return self.delete(tag)
      end
    else
      # Retrieval:
      return self[tag] rescue nil
    end
  end
  # Forward to Object#method_missing:
  super
end

Instance Method Details

#[](tag_or_index) ⇒ Element, ...

Retrieves the child element matching the specified element tag or item index.

Only immediate children are searched. Grandchildren etc. are not included.

Examples:

Extract the “Pixel Data” data element from the DObject instance

pixel_data_element = dcm["7FE0,0010"]

Extract the first Item from a Sequence

first_item = dcm["3006,0020"][0]

Parameters:

  • tag_or_index (String, Integer)

    a ruby-dicom tag string or item index

Returns:



27
28
29
30
# File 'lib/dicom/parent.rb', line 27

def [](tag_or_index)
  formatted = tag_or_index.is_a?(String) ? tag_or_index.upcase : tag_or_index
  return @tags[formatted]
end

#add(element, options = {}) ⇒ Object

Note:

Items can not be added with this method (use add_item instead).

Adds an Element or Sequence instance to self (where self can be either a DObject or an Item).

option options [Boolean] :no_follow when true, the method does not update the parent attribute of the child that is added

Examples:

Set a new patient’s name to the DICOM object

dcm.add(Element.new("0010,0010", "John_Doe"))

Add a previously defined element roi_name to the first item of a sequence

dcm["3006,0020"][0].add(roi_name)

Parameters:

  • element (Element, Sequence)

    a child element/sequence

  • options (Hash) (defaults to: {})

    the options used for adding the element/sequence



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/dicom/parent.rb', line 44

def add(element, options={})
  unless element.is_a?(Item)
    unless self.is_a?(Sequence)
      # Does the element's binary value need to be reencoded?
      reencode = true if element.is_a?(Element) && element.endian != stream.str_endian
      # If we are replacing an existing Element, we need to make sure that this Element's parent value is erased before proceeding.
      self[element.tag].parent = nil if exists?(element.tag)
      # Add the element, and set its parent attribute:
      @tags[element.tag] = element
      element.parent = self unless options[:no_follow]
      # As the element has been moved in place, perform re-encode if indicated:
      element.value = element.value if reencode
    else
      raise "A Sequence is only allowed to have Item elements added to it. Use add_item() instead if the intention is to add an Item."
    end
  else
    raise ArgumentError, "An Item is not allowed as a parameter to the add() method. Use add_item() instead."
  end
end

#add_item(item = nil, options = {}) ⇒ Object

Note:

Items are specified by index (starting at 0) instead of a tag string!

Adds a child item to a Sequence (or Item in some cases where pixel data is encapsulated).

If no existing Item is given, a new item will be created and added.

option options [Integer] :if specified, forces the item to be inserted at that specific index (Item number) option options [Boolean] :no_follow when true, the method does not update the parent attribute of the child that is added

  • options – A hash of parameters.

Examples:

Add an empty Item to a specific Sequence

dcm["3006,0020"].add_item

Add an existing Item at the 2nd item position/index in the specific Sequence

dcm["3006,0020"].add_item(my_item, :index => 1)

Parameters:

  • item (Item) (defaults to: nil)

    the Item instance to be added

  • options (Hash) (defaults to: {})

    the options used for adding the item



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/dicom/parent.rb', line 80

def add_item(item=nil, options={})
  unless self.is_a?(DObject)
    if item
      if item.is_a?(Item)
        if options[:index]
          # This Item will take a specific index, and all existing Items with index higher or equal to this number will have their index increased by one.
          # Check if index is valid (must be an existing index):
          if options[:index] >= 0
            # If the index value is larger than the max index present, we dont need to modify the existing items.
            if options[:index] < @tags.length
              # Extract existing Hash entries to an array:
              pairs = @tags.sort
              @tags = Hash.new
              # Change the key of those equal or larger than index and put these key,value pairs back in a new Hash:
              pairs.each do |pair|
                if pair[0] < options[:index]
                  @tags[pair[0]] = pair[1] # (Item keeps its old index)
                else
                  @tags[pair[0]+1] = pair[1]
                  pair[1].index = pair[0]+1 # (Item gets updated with its new index)
                end
              end
            else
              # Set the index value one higher than the already existing max value:
              options[:index] = @tags.length
            end
            #,Add the new Item and set its index:
            @tags[options[:index]] = item
            item.index = options[:index]
          else
            raise ArgumentError, "The specified index (#{options[:index]}) is out of range (Must be a positive integer)."
          end
        else
          # Add the existing Item to this Sequence:
          index = @tags.length
          @tags[index] = item
          # Let the Item know what index key it's got in it's parent's Hash:
          item.index = index
        end
        # Set ourself as this item's new parent:
        item.set_parent(self) unless options[:no_follow]
      else
        raise ArgumentError, "The specified parameter is not an Item. Only Items are allowed to be added to a Sequence."
      end
    else
      # Create an empty Item with self as parent.
      index = @tags.length
      item = Item.new(:parent => self)
    end
  else
    raise "An Item #{item} was attempted added to a DObject instance #{self}, which is not allowed."
  end
end

#childrenArray<Element, Item, Sequence>

Retrieves all (immediate) child elementals in an array (sorted by element tag).

Examples:

Retrieve all top level elements in a DICOM object

top_level_elements = dcm.children

Returns:



140
141
142
# File 'lib/dicom/parent.rb', line 140

def children
  return @tags.sort.transpose[1] || Array.new
end

#children?Boolean

Checks if an element actually has any child elementals (elements/items/sequences).

Notice the subtle difference between the children? and is_parent? methods. While they will give the same result in most real use cases, they differ when used on parent elements that do not have any children added yet.

For example, when called on an empty Sequence, the children? method will return false, whereas the is_parent? method still returns true.

Returns:

  • (Boolean)

    true if the element has children, and false if not



155
156
157
158
159
160
161
# File 'lib/dicom/parent.rb', line 155

def children?
  if @tags.length > 0
    return true
  else
    return false
  end
end

#countInteger

Gives the number of elements connected directly to this parent.

This count does NOT include the number of elements contained in any possible child elements.

Returns:

  • (Integer)

    The number of child elements belonging to this parent



169
170
171
# File 'lib/dicom/parent.rb', line 169

def count
  return @tags.length
end

#count_allInteger

Gives the total number of elements connected to this parent.

This count includes all the elements contained in any possible child elements.

Returns:

  • (Integer)

    The total number of child elements connected to this parent



179
180
181
182
183
184
185
186
# File 'lib/dicom/parent.rb', line 179

def count_all
  # Iterate over all elements, and repeat recursively for all elements which themselves contain children.
  total_count = count
  @tags.each_value do |value|
    total_count += value.count_all if value.children?
  end
  return total_count
end

#delete(tag_or_index, options = {}) ⇒ Object

Deletes the specified element from this parent.

option options [Boolean] :no_follow when true, the method does not update the parent attribute of the child that is deleted

Examples:

Delete an Element from a DObject instance

dcm.delete("0008,0090")

Delete Item 1 from a Sequence

dcm["3006,0020"].delete(1)

Parameters:

  • tag_or_index (String, Integer)

    a ruby-dicom tag string or item index

  • options (Hash) (defaults to: {})

    the options used for deleting the element



198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/dicom/parent.rb', line 198

def delete(tag_or_index, options={})
  if tag_or_index.is_a?(String) or tag_or_index.is_a?(Integer)
    raise ArgumentError, "Argument (#{tag_or_index}) is not a valid tag string." if tag_or_index.is_a?(String) && !tag_or_index.tag?
    raise ArgumentError, "Negative Integer argument (#{tag_or_index}) is not allowed." if tag_or_index.is_a?(Integer) && tag_or_index < 0
  else
    raise ArgumentError, "Expected String or Integer, got #{tag_or_index.class}."
  end
  # We need to delete the specified child element's parent reference in addition to removing it from the tag Hash.
  element = self[tag_or_index]
  if element
    element.parent = nil unless options[:no_follow]
    @tags.delete(tag_or_index)
  end
end

#delete_childrenObject

Deletes all child elements from this parent.



215
216
217
218
219
# File 'lib/dicom/parent.rb', line 215

def delete_children
  @tags.each_key do |tag|
    delete(tag)
  end
end

#delete_group(group_string) ⇒ Object

Deletes all elements of the specified group from this parent.

Examples:

Delete the File Meta Group of a DICOM object

dcm.delete_group("0002")

Parameters:

  • group_string (String)

    a group string (the first 4 characters of a tag string)



227
228
229
230
231
232
# File 'lib/dicom/parent.rb', line 227

def delete_group(group_string)
  group_elements = group(group_string)
  group_elements.each do |element|
    delete(element.tag)
  end
end

#delete_privateObject

Deletes all private data/sequence elements from this parent.

Examples:

Delete all private elements from a DObject instance

dcm.delete_private

Delete only private elements belonging to a specific Sequence

dcm["3006,0020"].delete_private


241
242
243
244
245
246
247
# File 'lib/dicom/parent.rb', line 241

def delete_private
  # Iterate all children, and repeat recursively if a child itself has children, to delete all private data elements:
  children.each do |element|
    delete(element.tag) if element.tag.private?
    element.delete_private if element.children?
  end
end

#delete_retiredObject

Deletes all retired data/sequence elements from this parent.

Examples:

Delete all retired elements from a DObject instance

dcm.delete_retired


254
255
256
257
258
259
260
261
# File 'lib/dicom/parent.rb', line 254

def delete_retired
  # Iterate all children, and repeat recursively if a child itself has children, to delete all retired elements:
  children.each do |element|
    dict_element = LIBRARY.element(element.tag)
    delete(element.tag) if dict_element && dict_element.retired?
    element.delete_retired if element.children?
  end
end

#each(&block) ⇒ Object

Iterates all children of this parent, calling block for each child.



265
266
267
# File 'lib/dicom/parent.rb', line 265

def each(&block)
  children.each_with_index(&block)
end

#each_element(&block) ⇒ Object

Iterates the child elements of this parent, calling block for each element.



271
272
273
# File 'lib/dicom/parent.rb', line 271

def each_element(&block)
  elements.each_with_index(&block) if children?
end

#each_item(&block) ⇒ Object

Iterates the child items of this parent, calling block for each item.



277
278
279
# File 'lib/dicom/parent.rb', line 277

def each_item(&block)
  items.each_with_index(&block) if children?
end

#each_sequence(&block) ⇒ Object

Iterates the child sequences of this parent, calling block for each sequence.



283
284
285
# File 'lib/dicom/parent.rb', line 283

def each_sequence(&block)
  sequences.each_with_index(&block) if children?
end

#each_tag(&block) ⇒ Object

Iterates the child tags of this parent, calling block for each tag.



289
290
291
# File 'lib/dicom/parent.rb', line 289

def each_tag(&block)
  @tags.each_key(&block)
end

#elementsArray<Element>

Retrieves all child elements of this parent in an array.

Returns:

  • (Array<Element>)

    child elements (or empty array, if childless)



297
298
299
# File 'lib/dicom/parent.rb', line 297

def elements
  children.select { |child| child.is_a?(Element)}
end

#elements?Boolean

A boolean which indicates whether the parent has any child elements.

Returns:

  • (Boolean)

    true if any child elements exists, and false if not



305
306
307
# File 'lib/dicom/parent.rb', line 305

def elements?
  elements.any?
end

#encode_children(old_endian) ⇒ Object

Note:

This method is only intended for internal library use, but for technical reasons (the fact that is called between instances of different classes), can’t be made private.

Re-encodes the binary data strings of all child Element instances. This also includes all the elements contained in any possible child elements.

Parameters:

  • old_endian (Boolean)

    the previous endianness of the elements/DObject instance (used for decoding values from binary)



316
317
318
319
320
321
322
323
324
325
# File 'lib/dicom/parent.rb', line 316

def encode_children(old_endian)
   # Cycle through all levels of children recursively:
  children.each do |element|
    if element.children?
      element.encode_children(old_endian)
    elsif element.is_a?(Element)
      encode_child(element, old_endian)
    end
  end
end

#exists?(tag_or_index) ⇒ Boolean

Checks whether a specific data element tag is defined for this parent.

Examples:

Do something with an element only if it exists

process_name(dcm["0010,0010"]) if dcm.exists?("0010,0010")

Parameters:

  • tag_or_index (String, Integer)

    a ruby-dicom tag string or item index

Returns:

  • (Boolean)

    true if the element is found, and false if not



334
335
336
337
338
339
340
# File 'lib/dicom/parent.rb', line 334

def exists?(tag_or_index)
  if self[tag_or_index]
    return true
  else
    return false
  end
end

#group(group_string) ⇒ Array<Element, Item, Sequence>

Returns an array of all child elements that belongs to the specified group.

Parameters:

  • group_string (String)

    a group string (the first 4 characters of a tag string)

Returns:

Raises:

  • (ArgumentError)


347
348
349
350
351
352
353
354
# File 'lib/dicom/parent.rb', line 347

def group(group_string)
  raise ArgumentError, "Expected String, got #{group_string.class}." unless group_string.is_a?(String)
  found = Array.new
  children.each do |child|
    found << child if child.tag.group == group_string.upcase
  end
  return found
end

#handle_print(index, max_digits, max_name, max_length, max_generations, visualization, options = {}) ⇒ Array

Note:

This method is only intended for internal library use, but for technical reasons (the fact that is called between instances of different classes), can’t be made private. The method is used by the print() method to construct its text output.

Gathers the desired information from the selected data elements and processes this information to make a text output which is nicely formatted.

Parameters:

  • index (Integer)

    the index which is given to the first child of this parent

  • max_digits (Integer)

    the maximum number of digits in the index of an element (in reality the number of digits of the last element)

  • max_name (Integer)

    the maximum number of characters in the name of any element to be printed

  • max_length (Integer)

    the maximum number of digits in the length of an element

  • max_generations (Integer)

    the maximum number of generations of children for this parent

  • visualization (Integer)

    an array of string symbols which visualizes the tree structure that the children of this particular parent belongs to (for no visualization, an empty array is passed)

  • options (Hash) (defaults to: {})

    the options to use when processing the print information

Options Hash (options):

  • :value_max (Integer)

    if a value max length is specified, the element values which exceeds this are trimmed

Returns:

  • (Array)

    a text array and an index of the last element



373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
# File 'lib/dicom/parent.rb', line 373

def handle_print(index, max_digits, max_name, max_length, max_generations, visualization, options={})
  # FIXME: This method is somewhat complex, and some simplification, if possible, wouldn't hurt.
  elements = Array.new
  s = " "
  hook_symbol = "|_"
  last_item_symbol = "  "
  nonlast_item_symbol = "| "
  children.each_with_index do |element, i|
    n_parents = element.parents.length
    # Formatting: Index
    i_s = s*(max_digits-(index).to_s.length)
    # Formatting: Name (and Tag)
    if element.tag == ITEM_TAG
      # Add index numbers to the Item names:
      name = "#{element.name} (\##{i})"
    else
      name = element.name
    end
    n_s = s*(max_name-name.length)
    # Formatting: Tag
    tag = "#{visualization.join}#{element.tag}"
    t_s = s*((max_generations-1)*2+9-tag.length)
    # Formatting: Length
    l_s = s*(max_length-element.length.to_s.length)
    # Formatting Value:
    if element.is_a?(Element)
      value = element.value.to_s
    else
      value = ""
    end
    if options[:value_max]
      value = "#{value[0..(options[:value_max]-3)]}.." if value.length > options[:value_max]
    end
    elements << "#{i_s}#{index} #{tag}#{t_s} #{name}#{n_s} #{element.vr} #{l_s}#{element.length} #{value}"
    index += 1
    # If we have child elements, print those elements recursively:
    if element.children?
      if n_parents > 1
        child_visualization = Array.new
        child_visualization.replace(visualization)
        if element == children.first
          if children.length == 1
            # Last item:
            child_visualization.insert(n_parents-2, last_item_symbol)
          else
            # More items follows:
            child_visualization.insert(n_parents-2, nonlast_item_symbol)
          end
        elsif element == children.last
          # Last item:
          child_visualization[n_parents-2] = last_item_symbol
          child_visualization.insert(-1, hook_symbol)
        else
          # Neither first nor last (more items follows):
          child_visualization.insert(n_parents-2, nonlast_item_symbol)
        end
      elsif n_parents == 1
        child_visualization = Array.new(1, hook_symbol)
      else
        child_visualization = Array.new
      end
      new_elements, index = element.handle_print(index, max_digits, max_name, max_length, max_generations, child_visualization, options)
      elements << new_elements
    end
  end
  return elements.flatten, index
end

#inspectString

Gives a string containing a human-readable hash representation of the parent.

Returns:

  • (String)

    a hash representation string of the parent



445
446
447
# File 'lib/dicom/parent.rb', line 445

def inspect
  to_hash.inspect
end

#is_parent?Boolean

Checks if an elemental is a parent.

Returns:

  • (Boolean)

    true for all parent elementals (Item, Sequence, DObject)



453
454
455
# File 'lib/dicom/parent.rb', line 453

def is_parent?
  return true
end

#itemsArray<Item>

Retrieves all child items of this parent in an array.

Returns:

  • (Array<Item>)

    child items (or empty array, if childless)



461
462
463
# File 'lib/dicom/parent.rb', line 461

def items
  children.select { |child| child.is_a?(Item)}
end

#items?Boolean

A boolean which indicates whether the parent has any child items.

Returns:

  • (Boolean)

    true if any child items exists, and false if not



469
470
471
# File 'lib/dicom/parent.rb', line 469

def items?
  items.any?
end

#length=(new_length) ⇒ Object

Note:

Currently, ruby-dicom does not use sequence/item lengths when writing DICOM files

Sets the length of a Sequence or Item.

(it sets the length to -1, meaning UNDEFINED). Therefore, in practice, it isn’t necessary to use this method, at least as far as writing (valid) DICOM files is concerned.

Parameters:

  • new_length (Integer)

    the new length to assign to the Sequence/Item



481
482
483
484
485
486
487
# File 'lib/dicom/parent.rb', line 481

def length=(new_length)
  unless self.is_a?(DObject)
    @length = new_length
  else
    raise "Length can not be set for a DObject instance."
  end
end

#max_lengthsObject

Note:

This method is only intended for internal library use, but for technical reasons (the fact that is called between instances of different classes), can’t be made private. The method is used by the print() method to achieve a proper format in its output.

Finds and returns the maximum character lengths of name and length which occurs for any child element, as well as the maximum number of generations of elements.



496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
# File 'lib/dicom/parent.rb', line 496

def max_lengths
  max_name = 0
  max_length = 0
  max_generations = 0
  children.each do |element|
    if element.children?
      max_nc, max_lc, max_gc = element.max_lengths
      max_name = max_nc if max_nc > max_name
      max_length = max_lc if max_lc > max_length
      max_generations = max_gc if max_gc > max_generations
    end
    n_length = element.name.length
    l_length = element.length.to_s.length
    generations = element.parents.length
    max_name = n_length if n_length > max_name
    max_length = l_length if l_length > max_length
    max_generations = generations if generations > max_generations
  end
  return max_name, max_length, max_generations
end

Prints all child elementals of this particular parent. Information such as tag, parent-child relationship, name, vr, length and value is gathered for each element and processed to produce a nicely formatted output.

option options [Integer] :value_max if a value max length is specified, the element values which exceeds this are trimmed option options [String] :file if a file path is specified, the output is printed to this file instead of being printed to the screen

Examples:

Print a DObject instance to screen

dcm.print

Print the DObject to the screen, but specify a 25 character value cutoff to produce better-looking results

dcm.print(:value_max => 25)

Print to a text file the elements that belong to a specific Sequence

dcm["3006,0020"].print(:file => "dicom.txt")

Parameters:

  • options (Hash) (defaults to: {})

    the options to use for handling the printout

Returns:

  • (Array<String>)

    an array of formatted element string lines



575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
# File 'lib/dicom/parent.rb', line 575

def print(options={})
  # FIXME: Perhaps a :children => false option would be a good idea (to avoid lengthy printouts in cases where this would be desirable)?
  # FIXME: Speed. The new print algorithm may seem to be slower than the old one (observed on complex, hiearchical DICOM files). Perhaps it can be optimized?
  elements = Array.new
  # We first gather some properties that is necessary to produce a nicely formatted printout (max_lengths, count_all),
  # then the actual information is gathered (handle_print),
  # and lastly, we pass this information on to the methods which print the output (print_file or print_screen).
  if count > 0
    max_name, max_length, max_generations = max_lengths
    max_digits = count_all.to_s.length
    visualization = Array.new
    elements, index = handle_print(start_index=1, max_digits, max_name, max_length, max_generations, visualization, options)
    if options[:file]
      print_file(elements, options[:file])
    else
      print_screen(elements)
    end
  else
    puts "Notice: Object #{self} is empty (contains no data elements)!"
  end
  return elements
end

#reset_lengthObject

Resets the length of a Sequence or Item to -1, which is the number used for ‘undefined’ length.



600
601
602
603
604
605
606
607
# File 'lib/dicom/parent.rb', line 600

def reset_length
  unless self.is_a?(DObject)
    @length = -1
    @bin = ""
  else
    raise "Length can not be set for a DObject instance."
  end
end

#respond_to?(method, include_private = false) ⇒ Boolean

Checks if the parent responds to the given method (symbol) (whether the method is defined or not).

Parameters:

  • method (Symbol)

    a method name who’s response is tested

  • include_private (Boolean) (defaults to: false)

    if true, private methods are included in the search (not used by ruby-dicom)

Returns:

  • (Boolean)

    true if the parent responds to the given method (method is defined), and false if not



615
616
617
618
619
620
621
622
# File 'lib/dicom/parent.rb', line 615

def respond_to?(method, include_private=false)
  # Check the library for a tag corresponding to the given method name symbol:
  return true unless LIBRARY.as_tag(method.to_s).nil?
  # In case of a query (xxx?) or assign (xxx=), remove last character and try again:
  return true unless LIBRARY.as_tag(method.to_s[0..-2]).nil?
  # Forward to Object#respond_to?:
  super
end

#sequencesArray<Sequence>

Retrieves all child sequences of this parent in an array.

Returns:

  • (Array<Sequence>)

    child sequences (or empty array, if childless)



628
629
630
# File 'lib/dicom/parent.rb', line 628

def sequences
  children.select { |child| child.is_a?(Sequence) }
end

#sequences?Boolean

A boolean which indicates whether the parent has any child sequences.

Returns:

  • (Boolean)

    true if any child sequences exists, and false if not



636
637
638
# File 'lib/dicom/parent.rb', line 636

def sequences?
  sequences.any?
end

#to_hashHash

Builds a nested hash containing all children of this parent.

Keys are determined by the key_representation attribute, and data element values are used as values.

  • For private elements, the tag is used for key instead of the key representation, as private tags lacks names.

  • For child-less parents, the key_representation attribute is used as value.

Returns:

  • (Hash)

    a nested hash containing key & value pairs of all children



648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
# File 'lib/dicom/parent.rb', line 648

def to_hash
  as_hash = Hash.new
  unless children?
    if self.is_a?(DObject)
      as_hash = {}
    else
      as_hash[(self.tag.private?) ? self.tag : self.send(DICOM.key_representation)] = nil
    end
  else
    children.each do |child|
      if child.tag.private?
        hash_key = child.tag
      elsif child.is_a?(Item)
        hash_key = "Item #{child.index}"
      else
        hash_key = child.send(DICOM.key_representation)
      end
      if child.is_a?(Element)
        as_hash[hash_key] = child.to_hash[hash_key]
      else
        as_hash[hash_key] = child.to_hash
      end
    end
  end
  return as_hash
end

#to_jsonString

Builds a json string containing a human-readable representation of the parent.

Returns:

  • (String)

    a human-readable representation of this parent



679
680
681
# File 'lib/dicom/parent.rb', line 679

def to_json
  to_hash.to_json
end

#to_yamlString

Returns a yaml string containing a human-readable representation of the parent.

Returns:

  • (String)

    a human-readable representation of this parent



687
688
689
# File 'lib/dicom/parent.rb', line 687

def to_yaml
  to_hash.to_yaml
end

#value(tag) ⇒ String, ...

Gives the value of a specific Element child of this parent.

  • Only Element instances have values. Parent elements like Sequence and Item have no value themselves.

  • If the specified tag is that of a parent element, an exception is raised.

Examples:

Get the patient’s name value

name = dcm.value("0010,0010")

Get the Frame of Reference UID from the first item in the Referenced Frame of Reference Sequence

uid = dcm["3006,0010"][0].value("0020,0052")

Parameters:

  • tag (String)

    a tag string which identifies the child Element

Returns:

  • (String, Integer, Float, NilClass)

    an element value (or nil, if no element is matched)



703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
# File 'lib/dicom/parent.rb', line 703

def value(tag)
  if tag.is_a?(String) or tag.is_a?(Integer)
    raise ArgumentError, "Argument (#{tag}) is not a valid tag string." if tag.is_a?(String) && !tag.tag?
    raise ArgumentError, "Negative Integer argument (#{tag}) is not allowed." if tag.is_a?(Integer) && tag < 0
  else
    raise ArgumentError, "Expected String or Integer, got #{tag.class}."
  end
  if exists?(tag)
    if self[tag].is_parent?
      raise ArgumentError, "Illegal parameter '#{tag}'. Parent elements, like the referenced '#{@tags[tag].class}', have no value. Only Element tags are valid."
    else
      return self[tag].value
    end
  else
    return nil
  end
end