lib/hierarchy_string.rb in markdown_exec-2.3.0 vs lib/hierarchy_string.rb in markdown_exec-2.4.0
- old
+ new
@@ -1,14 +1,41 @@
# frozen_string_literal: true
+require_relative 'ansi_string'
+
# Class representing a hierarchy of substrings stored as Hash nodes
+# HierarchyString is a class that represents and manipulates strings based on a hierarchical structure.
+# The input to the class can be a single hash or an array of nested hashes, where each hash contains a
+# text string and an optional decoration or transformation (like `:downcase`, `:upcase`, etc.).
+#
+# The primary functionalities of the class include:
+#
+# - **Initialization**: The class can be initialized with either a single hash or an array of nested hashes.
+# Each hash contains a @text_sym key representing the string and a @style_sym key representing the transformation
+# (optional).
+#
+# - **Concatenation**: The `concatenate` method concatenates all text strings in the hierarchy into a single string.
+#
+# - **Decoration**: The `decorate` method applies the specified transformation (like `:downcase`, `:upcase`) to the
+# text in the hierarchy and returns the decorated string.
+#
+# - **Text Replacement**: The `replace_text!` method allows in-place replacement of text in the hierarchy by applying
+# a block to each text string.
+#
+# - **Method Delegation**: The class uses `method_missing` and `respond_to_missing?` to delegate undefined method calls
+# to the string object, allowing for dynamic method handling on the concatenated string (e.g., `capitalize`).
+#
+# This class is useful for situations where strings are represented in a hierarchical or nested structure and need
+# to be manipulated or transformed in a consistent and customizable manner.
class HierarchyString
attr_accessor :substrings
# Initialize with a single hash or an array of hashes
- def initialize(substrings)
+ def initialize(substrings, text_sym: :text, style_sym: :color)
@substrings = parse_substrings(substrings)
+ @text_sym = text_sym
+ @style_sym = style_sym
end
def map_substring_text_yield(tree, &block)
case tree
when Array
@@ -19,12 +46,12 @@
else
map_substring_text_yield(node, &block)
end
end
when Hash
- text = yield tree[:text]
- tree[:text] = text
+ text = yield tree[@text_sym]
+ tree[@text_sym] = text
tree
when String
yield tree
else
@@ -35,12 +62,12 @@
# operate on substring
def replace_text!
map_substring_text_yield(@substrings) do |node|
case node
when Hash
- text = yield node[:text]
- node[:text] = text
+ text = yield node[@text_sym]
+ node[@text_sym] = text
when String
yield node
end
end
end
@@ -87,11 +114,11 @@
# Recursively concatenate substrings
def concatenate_substrings(substrings)
substrings.map do |s|
case s
when Hash
- s[:text]
+ s[@text_sym]
when Array
concatenate_substrings(s)
end
end.join
end
@@ -99,35 +126,96 @@
# Recursively decorate substrings
def decorate_substrings(substrings, prior_color = '')
substrings.map do |s|
case s
when Hash
- if s[:color]
- s[:text].send(s[:color]) + prior_color
+ if s[@style_sym]
+ AnsiString.new(s[@text_sym]).send(s[@style_sym]) + prior_color
else
- s[:text]
+ s[@text_sym]
end
when Array
decorate_substrings(s, prior_color)
end
end.join
end
end
return if $PROGRAM_NAME != __FILE__
-# require 'bundler/setup'
-# Bundler.require(:default)
+require 'minitest/autorun'
-# require 'fcb'
-# require 'minitest/autorun'
+class TestHierarchyString < Minitest::Test
+ def setup
+ text_sym = :text
+ style_sym = :color
-# Usage
-hierarchy = HierarchyString.new([{ text: 'Hello ', color: :red },
- [{ text: 'World', color: :upcase },
- { text: '!' }]])
-puts hierarchy.decorate
-puts hierarchy.length
-# puts hierarchy.concatenate # Outputs: Hello World!
-# puts hierarchy.upcase # Outputs: HELLO WORLD!
-# puts hierarchy.length # Outputs: 12
-# puts hierarchy.gsub('World', 'Ruby') # Outputs: Hello Ruby!
+ @single_hash = { text_sym => 'Hello', style_sym => :downcase }
+ @nested_hashes = [
+ { text_sym => 'Hello', style_sym => :downcase },
+ [
+ { text_sym => ' ', style_sym => nil },
+ { text_sym => 'World', style_sym => :upcase }
+ ]
+ ]
+ @hierarchy_single = HierarchyString.new(@single_hash)
+ @hierarchy_nested = HierarchyString.new(@nested_hashes)
+ end
+
+ def test_initialize_single_hash
+ text_sym = :text
+ style_sym = :color
+
+ assert_equal [{ text_sym => 'Hello', style_sym => :downcase }],
+ @hierarchy_single.substrings
+ end
+
+ def test_initialize_nested_hashes
+ text_sym = :text
+ style_sym = :color
+
+ expected = [
+ [{ text_sym => 'Hello', style_sym => :downcase }],
+ [
+ [{ text_sym => ' ', style_sym => nil }],
+ [{ text_sym => 'World', style_sym => :upcase }]
+ ]
+ ]
+ assert_equal expected, @hierarchy_nested.substrings
+ end
+
+ def test_concatenate_single_hash
+ assert_equal 'Hello', @hierarchy_single.concatenate
+ end
+
+ def test_concatenate_nested_hashes
+ assert_equal 'Hello World', @hierarchy_nested.concatenate
+ end
+
+ def test_decorate_single_hash
+ assert_equal 'Hello'.downcase, @hierarchy_single.decorate
+ end
+
+ def test_decorate_nested_hashes
+ assert_equal "#{'Hello'.downcase} #{'World'.upcase}",
+ @hierarchy_nested.decorate
+ end
+
+ def test_replace_text_single_hash
+ @hierarchy_single.replace_text!(&:upcase)
+ assert_equal 'HELLO', @hierarchy_single.concatenate
+ end
+
+ def test_replace_text_nested_hashes
+ @hierarchy_nested.replace_text!(&:upcase)
+ assert_equal 'HELLO WORLD', @hierarchy_nested.concatenate
+ end
+
+ def test_method_missing
+ assert_equal 'Hello', @hierarchy_single.capitalize
+ end
+
+ def test_respond_to_missing
+ assert @hierarchy_single.respond_to?(:capitalize)
+ refute @hierarchy_single.respond_to?(:non_existent_method)
+ end
+end