livetext 0.9.55 → 0.9.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/livetext/ast/show_ast_clean.rb +10 -0
  3. data/lib/livetext/ast/show_ast_result.rb +60 -0
  4. data/lib/livetext/ast/show_raw_arrays.rb +13 -0
  5. data/lib/livetext/ast.rb +464 -0
  6. data/lib/livetext/ast_to_html.rb +32 -0
  7. data/lib/livetext/core.rb +6 -4
  8. data/lib/livetext/errors.rb +1 -0
  9. data/lib/livetext/functions.rb +26 -0
  10. data/lib/livetext/handler/mixin.rb +28 -0
  11. data/lib/livetext/helpers.rb +19 -20
  12. data/lib/livetext/standard.rb +2 -2
  13. data/lib/livetext/userapi.rb +20 -1
  14. data/lib/livetext/variable_manager.rb +14 -1
  15. data/lib/livetext/variables.rb +5 -1
  16. data/lib/livetext/version.rb +1 -1
  17. data/plugin/booktool.rb +6 -6
  18. data/plugin/lt3scriptor.rb +914 -0
  19. data/plugin/mixin_functions_class.rb +33 -0
  20. data/test/snapshots/error_missing_end/match-error.txt +1 -1
  21. data/test/snapshots/mixin_functions_class/expected-error.txt +0 -0
  22. data/test/snapshots/mixin_functions_class/expected-output.txt +20 -0
  23. data/test/snapshots/mixin_functions_class/mixin_functions_class.rb +33 -0
  24. data/test/snapshots/mixin_functions_class/source.lt3 +17 -0
  25. data/test/snapshots/system_info/match-output.txt +18 -0
  26. data/test/unit/all.rb +3 -0
  27. data/test/unit/ast.rb +90 -0
  28. data/test/unit/ast_directives.rb +104 -0
  29. data/test/unit/ast_variables.rb +71 -0
  30. data/test/unit/core_methods.rb +180 -0
  31. data/test/unit/formatter_component.rb +1 -1
  32. data/test/unit/mixin_functions_class.rb +131 -0
  33. data/test/unit/stringparser.rb +14 -32
  34. metadata +18 -5
  35. data/imports/markdown.rb +0 -44
  36. data/plugin/markdown.rb +0 -43
  37. data/test/snapshots/system_info/expected-output.txt +0 -18
@@ -0,0 +1,33 @@
1
+ def some_dot_command(args, data)
2
+ # This is a dot command, not a function
3
+ api.out "Dot command called with: #{data}"
4
+ end
5
+
6
+ class Livetext::Functions
7
+ def class_func(param)
8
+ "Class function called with: #{param}"
9
+ end
10
+
11
+ def another_class_func(param)
12
+ "Another class function called with: #{param}"
13
+ end
14
+
15
+ def simple_class_func
16
+ "Simple class function with no parameters"
17
+ end
18
+
19
+ def vars_test(param)
20
+ # New approach: Access variables through the instance variables
21
+ # @live and @vars are now available in Livetext::Functions
22
+
23
+ # Access variables using the new instance-based approach
24
+ view_var = @live.vars.View || "no_view"
25
+
26
+ # Alternative approaches:
27
+ # view_var = @vars.View || "no_view" # Direct access to vars
28
+ # view_var = get_var(:View) || "no_view" # Using helper method
29
+ # view_var = Livetext::Vars[:View] || "no_view" # Fallback to global
30
+
31
+ "Vars test: param=#{param}, View=#{view_var}"
32
+ end
33
+ end
@@ -1 +1 @@
1
- 1 /Expected .end, found end of file/
1
+ 1 /expected .end but found end of file/
@@ -0,0 +1,20 @@
1
+ Testing functions defined in Livetext::Functions class
2
+ <p>
3
+
4
+ Now calling functions defined in Livetext::Functions class:
5
+ Class function called with: test_parameter
6
+ <p>
7
+
8
+ And another one with brackets:
9
+ Another class function called with: with brackets
10
+ <p>
11
+
12
+ And a function with no parameters:
13
+ Simple class function with no parameters
14
+ <p>
15
+
16
+ Testing that the functions have access to Livetext::Vars:
17
+ Vars test: param=some_value, View=[View is undefined]
18
+ <p>
19
+
20
+ That's all.
@@ -0,0 +1,33 @@
1
+ def some_dot_command(args, data)
2
+ # This is a dot command, not a function
3
+ api.out "Dot command called with: #{data}"
4
+ end
5
+
6
+ class Livetext::Functions
7
+ def class_func(param)
8
+ "Class function called with: #{param}"
9
+ end
10
+
11
+ def another_class_func(param)
12
+ "Another class function called with: #{param}"
13
+ end
14
+
15
+ def simple_class_func
16
+ "Simple class function with no parameters"
17
+ end
18
+
19
+ def vars_test(param)
20
+ # New approach: Access variables through the instance variables
21
+ # @live and @vars are now available in Livetext::Functions
22
+
23
+ # Access variables using the new instance-based approach
24
+ view_var = @live.vars.View || "no_view"
25
+
26
+ # Alternative approaches:
27
+ # view_var = @vars.View || "no_view" # Direct access to vars
28
+ # view_var = get_var(:View) || "no_view" # Using helper method
29
+ # view_var = Livetext::Vars[:View] || "no_view" # Fallback to global
30
+
31
+ "Vars test: param=#{param}, View=#{view_var}"
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ Testing functions defined in Livetext::Functions class
2
+
3
+ .mixin mixin_functions_class
4
+
5
+ Now calling functions defined in Livetext::Functions class:
6
+ $$class_func:test_parameter
7
+
8
+ And another one with brackets:
9
+ $$another_class_func[with brackets]
10
+
11
+ And a function with no parameters:
12
+ $$simple_class_func
13
+
14
+ Testing that the functions have access to Livetext::Vars:
15
+ $$vars_test:some_value
16
+
17
+ That's all.
@@ -0,0 +1,18 @@
1
+ 1 System Info Variables:
2
+ 2 Hostname: HAL9000
3
+ 3 /Platform: .*x86_64-darwin\d+/
4
+ 4 /Ruby Version: \d+\.\d+\.\d+/
5
+ 5 Livetext Version: 0.9.55
6
+ 6 <p>
7
+ 7
8
+ 8 System Info Functions:
9
+ 9 Hostname: HAL9000
10
+ 10 /Platform: .*x86_64-darwin\d+/
11
+ 11 /Ruby Version: \d+\.\d+\.\d+/
12
+ 12 Livetext Version: 0.9.55
13
+ 13 <p>
14
+ 14
15
+ 15 Date Formatting Functions:
16
+ 16 /Default: \d{4}-\d{2}-\d{2}/
17
+ 17 /Days ago: \d{4}-\d{2}-\d{2}/
18
+ 18 /Days from now: \d{4}-\d{2}-\d{2}/
data/test/unit/all.rb CHANGED
@@ -10,6 +10,9 @@ require_relative 'variables'
10
10
  require_relative 'variable_manager'
11
11
  require_relative 'functions'
12
12
  require_relative 'function_registry'
13
+ require_relative 'mixin_functions_class'
13
14
  require_relative 'formatter'
15
+ require_relative 'formatter_component'
14
16
  require_relative 'core_methods'
17
+ require_relative 'stringparser'
15
18
 
data/test/unit/ast.rb ADDED
@@ -0,0 +1,90 @@
1
+ require 'minitest/autorun'
2
+
3
+ require_relative '../../lib/livetext/ast'
4
+
5
+ class TestingLivetextAST < Minitest::Test
6
+ def setup
7
+ @ast = LivetextAST.new
8
+ end
9
+
10
+ def test_ast_initialization
11
+ # Test that AST is properly initialized
12
+ assert(@ast, "AST should be initialized")
13
+ assert_instance_of(LivetextAST, @ast)
14
+ end
15
+
16
+ def test_basic_formatting
17
+ # Test basic text formatting
18
+ assert_equal([:bold, "bold"], @ast.parse_inline_formatting("*bold"))
19
+ assert_equal([:italic, "italic"], @ast.parse_inline_formatting("_italic"))
20
+ assert_equal([:code, "code"], @ast.parse_inline_formatting("`code"))
21
+ assert_equal([:strike, "strike"], @ast.parse_inline_formatting("~strike"))
22
+ end
23
+
24
+ def test_double_markers
25
+ # Test double markers
26
+ assert_equal([:bold, "bold"], @ast.parse_inline_formatting("**bold"))
27
+ assert_equal("**", @ast.parse_inline_formatting("**")) # standalone
28
+ assert_equal(" ** ", @ast.parse_inline_formatting(" ** ")) # surrounded by spaces
29
+ end
30
+
31
+ def test_bracketed_markers
32
+ # Test bracketed markers
33
+ assert_equal([:bold, "content"], @ast.parse_inline_formatting("*[content]"))
34
+ assert_equal([:italic, "content"], @ast.parse_inline_formatting("_[content]"))
35
+ assert_equal([:code, "content"], @ast.parse_inline_formatting("`[content]"))
36
+ assert_equal([], @ast.parse_inline_formatting("*[]")) # empty brackets disappear
37
+ end
38
+
39
+ def test_escaped_markers
40
+ # Test escaped markers
41
+ assert_equal("*literal", @ast.parse_inline_formatting("\\*literal"))
42
+ assert_equal("_literal", @ast.parse_inline_formatting("\\_literal"))
43
+ assert_equal("`literal", @ast.parse_inline_formatting("\\`literal"))
44
+ assert_equal("~literal", @ast.parse_inline_formatting("\\~literal"))
45
+ end
46
+
47
+ def test_mixed_content
48
+ # Test mixed content with text and formatting
49
+ assert_equal([:text, [:bold, "bold"], " text"], @ast.parse_inline_formatting("*bold text"))
50
+ assert_equal([:text, "Hello ", [:bold, "world!"]], @ast.parse_inline_formatting("Hello *world!"))
51
+ assert_equal([:text, [:bold, "bold,"], " ", [:italic, "italic,"], " and ", [:code, "code"]],
52
+ @ast.parse_inline_formatting("*bold, _italic, and `code"))
53
+ end
54
+
55
+ def test_double_marker_termination
56
+ # Test double markers ending at comma and period
57
+ assert_equal([:text, [:bold, "word"], ", text"], @ast.parse_inline_formatting("**word, text"))
58
+ assert_equal([:text, [:bold, "word"], ". text"], @ast.parse_inline_formatting("**word. text"))
59
+ end
60
+
61
+ def test_edge_cases
62
+ # Test edge cases
63
+ assert_equal([], @ast.parse_inline_formatting(nil))
64
+ assert_equal([], @ast.parse_inline_formatting(""))
65
+ assert_equal("plain text", @ast.parse_inline_formatting("plain text"))
66
+ end
67
+
68
+ def test_complex_examples
69
+ # Test more complex examples
70
+ input = "Hello *world and **bold, text with _italic and `code"
71
+ expected = [:text, "Hello ", [:bold, "world"], " and ", [:bold, "bold"], ", text with ", [:italic, "italic"], " and ", [:code, "code"]]
72
+ assert_equal(expected, @ast.parse_inline_formatting(input))
73
+ end
74
+
75
+ def test_bracketed_with_spaces
76
+ # Test bracketed markers with spaces
77
+ assert_equal([:text, [:bold, "This whole thing"], " is bold"],
78
+ @ast.parse_inline_formatting("*[This whole thing] is bold"))
79
+ assert_equal([:text, [:italic, "Important note"], " here"],
80
+ @ast.parse_inline_formatting("_[Important note] here"))
81
+ end
82
+
83
+ def test_escaped_in_context
84
+ # Test escaped markers in context
85
+ assert_equal("Literal *asterisks* here",
86
+ @ast.parse_inline_formatting("Literal \\*asterisks\\* here"))
87
+ assert_equal([:text, "Mixed ", [:bold, "bold"], " and *literal* text"],
88
+ @ast.parse_inline_formatting("Mixed *bold and \\*literal\\* text"))
89
+ end
90
+ end
@@ -0,0 +1,104 @@
1
+ require 'minitest/autorun'
2
+
3
+ require_relative '../../lib/livetext/ast'
4
+
5
+ class TestingLivetextASTDirectives < Minitest::Test
6
+ def setup
7
+ @ast = LivetextAST.new
8
+ end
9
+
10
+ def test_single_line_directives
11
+ # Single line directives (2 parameters: args, data)
12
+ assert_equal([LivetextAST::DIRECTIVE, "h1", "My Title"],
13
+ @ast.parse_directives([".h1 My Title"]))
14
+
15
+ assert_equal([LivetextAST::DIRECTIVE, "set", "name=value"],
16
+ @ast.parse_directives([".set name=value"]))
17
+
18
+ assert_equal([LivetextAST::DIRECTIVE, "comment", "This is a comment"],
19
+ @ast.parse_directives([". This is a comment"]))
20
+ end
21
+
22
+ def test_multi_line_comment_directive
23
+ # Multi-line .comment directive
24
+ input = [
25
+ ".comment",
26
+ " This is a multi-line comment",
27
+ " It can span multiple lines",
28
+ ".end"
29
+ ]
30
+ expected = [
31
+ LivetextAST::DIRECTIVE, "comment", "",
32
+ [LivetextAST::BODY, [" This is a multi-line comment", " It can span multiple lines"]]
33
+ ]
34
+ assert_equal(expected, @ast.parse_directives(input))
35
+ end
36
+
37
+ def test_multi_line_directives
38
+ # Multi line directives (3 parameters: args, data, body)
39
+ input = [
40
+ ".list",
41
+ " * item 1",
42
+ " * item 2",
43
+ " * item 3",
44
+ ".end"
45
+ ]
46
+ expected = [
47
+ LivetextAST::DIRECTIVE, "list", "",
48
+ [LivetextAST::BODY, [" * item 1", " * item 2", " * item 3"]]
49
+ ]
50
+ assert_equal(expected, @ast.parse_directives(input))
51
+ end
52
+
53
+ def test_directive_with_args_and_body
54
+ input = [
55
+ ".func myfunc",
56
+ " return 'Hello, World!'",
57
+ ".end"
58
+ ]
59
+ expected = [
60
+ LivetextAST::DIRECTIVE, "func", "myfunc",
61
+ [LivetextAST::BODY, [" return 'Hello, World!'"]]
62
+ ]
63
+ assert_equal(expected, @ast.parse_directives(input))
64
+ end
65
+
66
+ def test_missing_end_error
67
+ input = [
68
+ ".list",
69
+ " * item 1",
70
+ " * item 2"
71
+ # Missing .end
72
+ ]
73
+ expected = [
74
+ LivetextAST::ERROR, "Missing .end", 1, "list"
75
+ ]
76
+ assert_equal(expected, @ast.parse_directives(input))
77
+ end
78
+
79
+ def test_unknown_directive
80
+ input = [".unknown_directive some args"]
81
+ expected = [
82
+ LivetextAST::ERROR, "Unknown directive", 1, "unknown_directive"
83
+ ]
84
+ assert_equal(expected, @ast.parse_directives(input))
85
+ end
86
+
87
+ def test_empty_input
88
+ assert_equal([], @ast.parse_directives([]))
89
+ assert_equal([], @ast.parse_directives(nil))
90
+ end
91
+
92
+ def test_non_directive_lines
93
+ input = [
94
+ "Just some text",
95
+ "More text here",
96
+ ".h1 A Title",
97
+ "More text"
98
+ ]
99
+ expected = [
100
+ LivetextAST::DIRECTIVE, "h1", "A Title"
101
+ ]
102
+ assert_equal(expected, @ast.parse_directives(input))
103
+ end
104
+ end
@@ -0,0 +1,71 @@
1
+ require 'minitest/autorun'
2
+
3
+ require_relative '../../lib/livetext/ast'
4
+
5
+ class TestingLivetextASTVariables < Minitest::Test
6
+ def setup
7
+ @ast = LivetextAST.new
8
+ end
9
+
10
+ def test_variable_parsing
11
+ # Basic variables
12
+ assert_equal([LivetextAST::VAR, "name"], @ast.parse_variables("$name"))
13
+ assert_equal([LivetextAST::VAR, "my_var"], @ast.parse_variables("$my_var"))
14
+ assert_equal([LivetextAST::VAR, "font.title"], @ast.parse_variables("$font.title"))
15
+
16
+ # Invalid names should be left as literal text
17
+ assert_equal("$_invalid", @ast.parse_variables("$_invalid"))
18
+ assert_equal("$3invalid", @ast.parse_variables("$3invalid"))
19
+
20
+ # Edge cases - Livetext behavior:
21
+ # $foo. -> parses $foo as variable, . as literal (matches Livetext)
22
+ assert_equal([LivetextAST::TEXT, [LivetextAST::VAR, "foo"], "."], @ast.parse_variables("$foo."))
23
+ # $a..b -> parses $a as variable, ..b as literal (matches Livetext)
24
+ assert_equal([LivetextAST::TEXT, [LivetextAST::VAR, "a"], "..b"], @ast.parse_variables("$a..b"))
25
+ end
26
+
27
+ def test_function_parsing
28
+ # No parameter
29
+ assert_equal([LivetextAST::FUNC, "myfunc", LivetextAST::SPACE, nil], @ast.parse_functions("$$myfunc "))
30
+ assert_equal([LivetextAST::FUNC, "myfunc", LivetextAST::EOL, nil], @ast.parse_functions("$$myfunc"))
31
+
32
+ # Colon parameter
33
+ assert_equal([LivetextAST::FUNC, "greet", LivetextAST::COLON, "world"], @ast.parse_functions("$$greet:world"))
34
+
35
+ # Bracket parameter
36
+ assert_equal([LivetextAST::FUNC, "mean", LivetextAST::LBRACK, "1,2,3"], @ast.parse_functions("$$mean[1,2,3]"))
37
+ assert_equal([LivetextAST::FUNC, "title", LivetextAST::LBRACK, "My Title"], @ast.parse_functions("$$title[My Title]"))
38
+
39
+ # Note: Function parameter delimiters are tracked as requested:
40
+ # SPACE, EOL, COLON, LBRACK for debugging/future use
41
+ end
42
+
43
+ def test_mixed_content
44
+ # Variables in text
45
+ input = "Hello $name, welcome to $nation!"
46
+ expected = [LivetextAST::TEXT, "Hello ", [LivetextAST::VAR, "name"], ", welcome to ", [LivetextAST::VAR, "nation"], "!"]
47
+ assert_equal(expected, @ast.parse_variables(input))
48
+
49
+ # Functions in text
50
+ input = "The result is $$mean[1,2,3] as expected."
51
+ expected = [LivetextAST::TEXT, "The result is ", [LivetextAST::FUNC, "mean", LivetextAST::LBRACK, "1,2,3"], " as expected."]
52
+ assert_equal(expected, @ast.parse_functions(input))
53
+ end
54
+
55
+ def test_escaped_dollars
56
+ # Escaped variables and functions
57
+ # Note: Backslash escapes the entire $ or $$ sequence
58
+ assert_equal("\\$literal", @ast.parse_variables("\\$literal"))
59
+ assert_equal("\\$\\$literal", @ast.parse_functions("\\$\\$literal"))
60
+ end
61
+
62
+ def test_edge_cases
63
+ # Empty strings
64
+ assert_equal([], @ast.parse_variables(""))
65
+ assert_equal([], @ast.parse_functions(""))
66
+
67
+ # No variables/functions
68
+ assert_equal("plain text", @ast.parse_variables("plain text"))
69
+ assert_equal("plain text", @ast.parse_functions("plain text"))
70
+ end
71
+ end
@@ -29,6 +29,186 @@ class TestingLivetextCoreMethods < Minitest::Test
29
29
  assert_equal(@live, result) # Should return self
30
30
  end
31
31
 
32
+ def test_customize_with_plugin
33
+ # Test customize with a real plugin
34
+ obj = Livetext.customize(
35
+ mix: ['tutorial'],
36
+ call: [],
37
+ vars: {}
38
+ )
39
+
40
+ assert_instance_of(Livetext, obj)
41
+ # Should have loaded the tutorial plugin
42
+ assert_includes(obj.methods, :title)
43
+ end
44
+
45
+ def test_customize_with_commands
46
+ # Test customize with dot commands
47
+ obj = Livetext.customize(
48
+ mix: [],
49
+ call: ['.set VAR="test_value"'],
50
+ vars: {}
51
+ )
52
+
53
+ assert_instance_of(Livetext, obj)
54
+ # Process some text to see if the variable was set
55
+ body, vars = obj.process(text: "Variable: $VAR")
56
+ assert_includes(body, "Variable: test_value")
57
+ end
58
+
59
+ def test_customize_with_variables
60
+ # Test customize with variables
61
+ obj = Livetext.customize(
62
+ mix: [],
63
+ call: [],
64
+ vars: { 'name' => 'World', 'title' => 'Test' }
65
+ )
66
+
67
+ assert_instance_of(Livetext, obj)
68
+ # Process some text to see if variables were set
69
+ body, vars = obj.process(text: "Hello $name\n.h1 $title")
70
+ assert_includes(body, "Hello World")
71
+ assert_includes(body, "Test")
72
+ end
73
+
74
+ def test_customize_comprehensive
75
+ # Test all features together
76
+ obj = Livetext.customize(
77
+ mix: ['tutorial'],
78
+ call: ['.set PLUGIN_VAR="plugin_value"'],
79
+ vars: { 'custom_var' => 'custom_value' }
80
+ )
81
+
82
+ assert_instance_of(Livetext, obj)
83
+
84
+ # Test that plugin was loaded
85
+ assert_includes(obj.methods, :title)
86
+
87
+ # Test that variables were set
88
+ body, vars = obj.process(text: "Plugin: $PLUGIN_VAR\nCustom: $custom_var")
89
+ assert_includes(body, "Plugin: plugin_value")
90
+ assert_includes(body, "Custom: custom_value")
91
+ end
92
+
93
+ def test_customize_error_handling
94
+ # Test customize with invalid plugin
95
+ assert_raises(FileNotFound) do
96
+ Livetext.customize(mix: ['nonexistent_plugin'])
97
+ end
98
+ end
99
+
100
+ def test_customize_empty_parameters
101
+ # Test customize with empty parameters
102
+ obj = Livetext.customize()
103
+ assert_instance_of(Livetext, obj)
104
+
105
+ # Should still work for basic processing
106
+ body, vars = obj.process(text: "Hello world")
107
+ assert_includes(body, "Hello world")
108
+ end
109
+
110
+ def test_customize_string_vs_array
111
+ # Test that string parameters are converted to arrays
112
+ obj = Livetext.customize(
113
+ mix: 'tutorial',
114
+ call: '.nopara',
115
+ vars: { 'test' => 'value' }
116
+ )
117
+
118
+ assert_instance_of(Livetext, obj)
119
+ assert_includes(obj.methods, :title)
120
+ end
121
+
122
+ def test_customize_variables_accessible
123
+ # Test that variables passed to customize are actually accessible afterward
124
+ obj = Livetext.customize(
125
+ mix: [],
126
+ call: [],
127
+ vars: { 'name' => 'World', 'title' => 'Test Title', 'count' => '42' }
128
+ )
129
+
130
+ assert_instance_of(Livetext, obj)
131
+
132
+ # Test that variables are accessible via vars.to_h
133
+ vars_hash = obj.vars.to_h
134
+ assert_equal('World', vars_hash[:name])
135
+ assert_equal('Test Title', vars_hash[:title])
136
+ assert_equal('42', vars_hash[:count])
137
+
138
+ # Test that variables are accessible via variables.to_h
139
+ variables_hash = obj.variables.to_h
140
+ assert_equal('World', variables_hash[:name])
141
+ assert_equal('Test Title', variables_hash[:title])
142
+ assert_equal('42', variables_hash[:count])
143
+
144
+ # Test that variables work in processing
145
+ body, vars = obj.process(text: "Hello $name\n.h1 $title\nCount: $count")
146
+ assert_includes(body, "Hello World")
147
+ assert_includes(body, "Test Title")
148
+ assert_includes(body, "Count: 42")
149
+ end
150
+
151
+ def test_customize_variables_global_access
152
+ # Test that variables passed to customize are accessible via Livetext::Vars
153
+ obj = Livetext.customize(
154
+ mix: [],
155
+ call: [],
156
+ vars: { 'name' => 'World', 'title' => 'Test Title', 'count' => '42' }
157
+ )
158
+
159
+ assert_instance_of(Livetext, obj)
160
+
161
+ # Test that variables are accessible via Livetext::Vars (global access)
162
+ assert_equal('World', Livetext::Vars[:name])
163
+ assert_equal('Test Title', Livetext::Vars[:title])
164
+ assert_equal('42', Livetext::Vars[:count])
165
+ end
166
+
167
+ def test_variable_dot_access
168
+ # Test that variables can be accessed via live.vars.myvar syntax
169
+ obj = Livetext.customize(
170
+ mix: [],
171
+ call: [],
172
+ vars: { 'name' => 'World', 'title' => 'Test Title', 'count' => '42' }
173
+ )
174
+
175
+ assert_instance_of(Livetext, obj)
176
+
177
+ # Test dot access syntax
178
+ assert_equal('World', obj.vars.name)
179
+ assert_equal('Test Title', obj.vars.title)
180
+ assert_equal('42', obj.vars.count)
181
+
182
+ # Test that built-in variables also work
183
+ assert_equal(Livetext::VERSION, obj.vars.Version)
184
+ assert_equal(`hostname`.chomp, obj.vars.Hostname)
185
+
186
+ # Test that respond_to? works correctly
187
+ assert(obj.vars.respond_to?(:name))
188
+ assert(obj.vars.respond_to?(:title))
189
+ assert(obj.vars.respond_to?(:Version))
190
+ assert(obj.vars.respond_to?(:nonexistent)) # Now returns true since method_missing always returns a value
191
+ end
192
+
193
+ def test_variable_dot_access_nonexistent
194
+ # Test what happens when accessing a nonexistent variable with dot syntax
195
+ obj = Livetext.customize(
196
+ mix: [],
197
+ call: [],
198
+ vars: { 'name' => 'World' }
199
+ )
200
+
201
+ assert_instance_of(Livetext, obj)
202
+
203
+ # Test that all access methods return the same fallback message
204
+ assert_equal('[nonexistent is undefined]', obj.vars.nonexistent)
205
+ assert_equal('[nonexistent is undefined]', obj.vars[:nonexistent])
206
+ assert_equal('[nonexistent is undefined]', obj.vars.get(:nonexistent))
207
+
208
+ # Test global access also returns fallback message
209
+ assert_equal('[nonexistent is undefined]', Livetext::Vars[:nonexistent])
210
+ end
211
+
32
212
  def test_process_text
33
213
  # Test processing text directly
34
214
  text = "Hello world\nThis is a test\n.h1 Title"
@@ -10,7 +10,7 @@ class TestingLivetextFormatter < Minitest::Test
10
10
  def test_formatter_component_initialization
11
11
  # Test that FormatterComponent is properly initialized
12
12
  assert(@live.formatter, "FormatterComponent should be initialized")
13
- assert_instance_of(Livetext::FormatterComponent, @live.formatter)
13
+ assert_instance_of(Livetext::Formatter, @live.formatter)
14
14
  end
15
15
 
16
16
  def test_basic_formatting