markdown_exec 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile.lock +2 -2
  4. data/Rakefile +3 -3
  5. data/bats/block-types.bats +13 -7
  6. data/bats/import.bats +6 -0
  7. data/bats/markup.bats +6 -15
  8. data/bats/options-collapse.bats +26 -0
  9. data/bats/options.bats +1 -1
  10. data/bats/table.bats +8 -0
  11. data/bats/test_helper.bash +74 -49
  12. data/bats/variable-expansion.bats +46 -0
  13. data/bin/tab_completion.sh +1 -1
  14. data/docs/dev/bats-document-configuration.md +8 -1
  15. data/docs/dev/block-type-bash.md +1 -1
  16. data/docs/dev/block-type-opts.md +1 -5
  17. data/docs/dev/block-type-vars.md +4 -0
  18. data/docs/dev/import-missing.md +2 -0
  19. data/docs/dev/menu-cli.md +1 -1
  20. data/docs/dev/options-collapse.md +47 -0
  21. data/docs/dev/requiring-blocks.md +3 -0
  22. data/docs/dev/specs.md +2 -1
  23. data/docs/dev/table-crash.md +39 -0
  24. data/docs/dev/table-indent.md +26 -0
  25. data/docs/dev/text-decoration.md +2 -5
  26. data/docs/dev/variable-expansion.md +2 -4
  27. data/examples/bash-blocks.md +1 -1
  28. data/examples/block-names.md +1 -1
  29. data/examples/block-types.md +1 -1
  30. data/examples/data-files.md +1 -1
  31. data/examples/document_options.md +2 -2
  32. data/examples/indent.md +1 -1
  33. data/examples/interrupt.md +1 -1
  34. data/examples/link-blocks-vars.md +1 -1
  35. data/examples/linked.md +1 -1
  36. data/examples/linked1.md +1 -1
  37. data/examples/nickname.md +1 -1
  38. data/examples/opts-blocks-require.md +1 -1
  39. data/examples/opts-blocks.md +1 -1
  40. data/examples/opts_output_execution.md +1 -1
  41. data/examples/pass-through-arguments.md +1 -1
  42. data/examples/pause-after-execution.md +1 -1
  43. data/examples/port-blocks.md +1 -1
  44. data/examples/save.md +1 -1
  45. data/examples/text-markup.md +1 -1
  46. data/examples/variable-expansion.md +6 -2
  47. data/examples/vars-blocks.md +1 -1
  48. data/examples/wrap.md +1 -1
  49. data/lib/block_types.rb +4 -0
  50. data/lib/cached_nested_file_reader.rb +7 -4
  51. data/lib/collapser.rb +302 -0
  52. data/lib/constants.rb +10 -0
  53. data/lib/evaluate_shell_expressions.rb +0 -3
  54. data/lib/fcb.rb +13 -17
  55. data/lib/format_table.rb +11 -7
  56. data/lib/hash_delegator.rb +461 -272
  57. data/lib/hierarchy_string.rb +5 -1
  58. data/lib/markdown_exec/version.rb +1 -1
  59. data/lib/markdown_exec.rb +16 -32
  60. data/lib/mdoc.rb +100 -35
  61. data/lib/menu.src.yml +124 -17
  62. data/lib/menu.yml +102 -16
  63. data/lib/ww.rb +75 -22
  64. metadata +12 -9
  65. data/lib/append_to_bash_history.rb +0 -303
  66. data/lib/ce_get_cost_and_usage.rb +0 -23
  67. data/lib/doh.rb +0 -190
  68. data/lib/layered_hash.rb +0 -143
  69. data/lib/poly.rb +0 -171
@@ -1,303 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # encoding=utf-8
5
-
6
- def append_to_bash_history(line)
7
- # Get the bash history file from the HISTFILE environment variable or default to ~/.bash_history
8
- histfile = ENV['HISTFILE'] || File.expand_path("~/.bash_history")
9
-
10
- if File.exist?(histfile)
11
- # Open the file in append mode and write the line
12
- File.open(histfile, 'a') do |file|
13
- file.puts line
14
- end
15
- puts "Appended to bash history: #{line}"
16
- else
17
- puts "Bash history file does not exist."
18
- end
19
- end
20
-
21
- return if $PROGRAM_NAME != __FILE__
22
-
23
- # Example usage:
24
- append_to_bash_history('echo "Hello from Ruby!"')
25
-
26
- # require 'minitest/autorun'
27
- # require_relative 'colorize'
28
-
29
- # class TestMarkdownTableFormatter < Minitest::Test
30
- # def setup
31
- # @lines = [
32
- # '| Header 1 | Header 2 | Header 3 |',
33
- # '|----------|:--------:|---------:|',
34
- # '| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |',
35
- # '| Row 2 Col 1 | Row 2 Col 2 | Row 2 Col 3 |'
36
- # ]
37
- # @column_count = 3
38
- # end
39
-
40
- # def test_format_table
41
- # result = MarkdownTableFormatter.format_table(
42
- # column_count: @column_count, lines: @lines
43
- # )
44
- # expected = [
45
- # '| Header 1 | Header 2 | Header 3 |',
46
- # '| ----------- | ----------- | ----------- |',
47
- # '| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |',
48
- # '| Row 2 Col 1 | Row 2 Col 2 | Row 2 Col 3 |'
49
- # ]
50
- # assert_equal expected, result
51
- # end
52
-
53
- # def test_format_table_with_decoration
54
- # decorate = { header_row: :upcase, row: %i[downcase upcase] }
55
- # result = MarkdownTableFormatter.format_table(
56
- # column_count: @column_count,
57
- # decorate: decorate,
58
- # lines: @lines
59
- # )
60
- # expected = [
61
- # '| HEADER 1 | HEADER 2 | HEADER 3 |',
62
- # '| ----------- | ----------- | ----------- |',
63
- # '| ROW 1 COL 1 | ROW 1 COL 2 | ROW 1 COL 3 |',
64
- # '| row 2 col 1 | row 2 col 2 | row 2 col 3 |'
65
- # ]
66
- # assert_equal expected, result
67
- # end
68
-
69
- # def test_format_table_with_empty_lines
70
- # lines_with_empty = [
71
- # '| Header 1 | Header 2 | Header 3 |',
72
- # '|----------|:--------:|---------:|',
73
- # '| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |',
74
- # '',
75
- # '| Row 2 Col 1 | Row 2 Col 2 | Row 2 Col 3 |'
76
- # ]
77
- # result = MarkdownTableFormatter.format_table(
78
- # lines: lines_with_empty,
79
- # column_count: @column_count
80
- # )
81
- # expected = [
82
- # '| Header 1 | Header 2 | Header 3 |',
83
- # '| ----------- | ----------- | ----------- |',
84
- # '| Row 1 Col 1 | Row 1 Col 2 | Row 1 Col 3 |',
85
- # '',
86
- # '| Row 2 Col 1 | Row 2 Col 2 | Row 2 Col 3 |'
87
- # ]
88
- # assert_equal expected, result
89
- # end
90
-
91
- # def test_alignment_detection
92
- # lines_with_alignment = [
93
- # '| Header 1 | Header 2 | Header 3 |',
94
- # '|:-------- |:--------:| --------:|'
95
- # ]
96
- # result = MarkdownTableFormatter.format_table(
97
- # lines: lines_with_alignment,
98
- # column_count: @column_count
99
- # )
100
- # expected = [
101
- # '| Header 1 | Header 2 | Header 3 |',
102
- # '| --------- | ---------- | --------- |'
103
- # ]
104
- # assert_equal expected, result[0..1] # only checking the header and separator
105
- # end
106
- # end
107
-
108
- # class TestFormatTable < Minitest::Test
109
- # def test_basic_formatting
110
- # lines = [
111
- # '| Species| Genus| Family',
112
- # '|-|-|-',
113
- # '| Pongo tapanuliensis| Pongo| Hominidae',
114
- # '| | Histiophryne| Antennariidae'
115
- # ]
116
- # column_count = 3
117
- # expected = [
118
- # '| Species | Genus | Family |',
119
- # '| ------------------- | ------------ | ------------- |',
120
- # '| Pongo tapanuliensis | Pongo | Hominidae |',
121
- # '| | Histiophryne | Antennariidae |'
122
- # ]
123
- # assert_equal expected, MarkdownTableFormatter.format_table(
124
- # lines: lines,
125
- # column_count: column_count
126
- # )
127
- # end
128
-
129
- # def test_missing_column_count
130
- # lines = [
131
- # '| A| B| C',
132
- # '| 1| 2',
133
- # '| X'
134
- # ]
135
- # column_count = 3
136
- # expected = [
137
- # '| A | B | C |',
138
- # '| 1 | 2 | |',
139
- # '| X | | |'
140
- # ]
141
- # assert_equal expected, MarkdownTableFormatter.format_table(
142
- # lines: lines,
143
- # column_count: column_count
144
- # )
145
- # end
146
-
147
- # # def test_extra_column_count
148
- # # lines = [
149
- # # "| A| B| C| D",
150
- # # "| 1| 2| 3| 4| 5"
151
- # # ]
152
- # # column_count = 3
153
- # # expected = [
154
- # # "| A | B | C ",
155
- # # "| 1 | 2 | 3 "
156
- # # ]
157
- # # assert_equal expected, MarkdownTableFormatter.format_table(lines, column_count)
158
- # # end
159
-
160
- # def test_empty_input
161
- # assert_equal [], MarkdownTableFormatter.format_table(
162
- # lines: [],
163
- # column_count: 3
164
- # )
165
- # end
166
-
167
- # def test_single_column
168
- # lines = [
169
- # '| A',
170
- # '| Longer text',
171
- # '| Short'
172
- # ]
173
- # column_count = 1
174
- # expected = [
175
- # '| A |',
176
- # '| Longer text |',
177
- # '| Short |'
178
- # ]
179
- # assert_equal expected, MarkdownTableFormatter.format_table(
180
- # lines: lines,
181
- # column_count: column_count
182
- # )
183
- # end
184
-
185
- # def test_no_pipe_at_end
186
- # lines = [
187
- # '| A| B| C',
188
- # '| 1| 2| 3'
189
- # ]
190
- # column_count = 3
191
- # expected = [
192
- # '| A | B | C |',
193
- # '| 1 | 2 | 3 |'
194
- # ]
195
- # assert_equal expected, MarkdownTableFormatter.format_table(
196
- # lines: lines,
197
- # column_count: column_count
198
- # )
199
- # end
200
- # end
201
-
202
- # class TestFormatTable2 < Minitest::Test
203
- # def test_basic_formatting
204
- # lines = [
205
- # '| Name | Age | City |',
206
- # '| John | 30 | New York |',
207
- # '| Jane | 25 | Los Angeles |'
208
- # ]
209
- # expected_output = [
210
- # '| Name | Age | City |',
211
- # '| John | 30 | New York |',
212
- # '| Jane | 25 | Los Angeles |'
213
- # ]
214
- # assert_equal expected_output, MarkdownTableFormatter.format_table(
215
- # lines: lines,
216
- # column_count: 3
217
- # )
218
- # end
219
-
220
- # def test_incomplete_column_count
221
- # lines = [
222
- # '| Name | Age |',
223
- # '| John | 30 | New York |',
224
- # '| Jane | 25 | Los Angeles |'
225
- # ]
226
- # expected_output = [
227
- # '| Name | Age | |',
228
- # '| John | 30 | New York |',
229
- # '| Jane | 25 | Los Angeles |'
230
- # ]
231
- # assert_equal expected_output, MarkdownTableFormatter.format_table(
232
- # lines: lines,
233
- # column_count: 3
234
- # )
235
- # end
236
-
237
- # def test_extra_column_count
238
- # lines = [
239
- # '| Name | Age | City | Country |',
240
- # '| John | 30 | New York | USA |',
241
- # '| Jane | 25 | Los Angeles | USA |'
242
- # ]
243
- # expected_output = [
244
- # '| Name | Age | City | Country |',
245
- # '| John | 30 | New York | USA |',
246
- # '| Jane | 25 | Los Angeles | USA |'
247
- # ]
248
- # assert_equal expected_output, MarkdownTableFormatter.format_table(
249
- # lines: lines,
250
- # column_count: 4
251
- # )
252
- # end
253
-
254
- # def test_varied_column_lengths
255
- # lines = [
256
- # '| Name | Age |',
257
- # '| Johnathan | 30 | New York |',
258
- # '| Jane | 25 | LA |'
259
- # ]
260
- # expected_output = [
261
- # '| Name | Age | |',
262
- # '| Johnathan | 30 | New York |',
263
- # '| Jane | 25 | LA |'
264
- # ]
265
- # assert_equal expected_output, MarkdownTableFormatter.format_table(
266
- # lines: lines,
267
- # column_count: 3
268
- # )
269
- # end
270
-
271
- # def test_single_line
272
- # lines = ['| Name | Age | City |']
273
- # expected_output = ['| Name | Age | City |']
274
- # assert_equal expected_output, MarkdownTableFormatter.format_table(
275
- # lines: lines,
276
- # column_count: 3
277
- # )
278
- # end
279
-
280
- # def test_empty_lines
281
- # lines = []
282
- # expected_output = []
283
- # assert_equal expected_output, MarkdownTableFormatter.format_table(
284
- # lines: lines,
285
- # column_count: 3
286
- # )
287
- # end
288
-
289
- # def test_complete_rows
290
- # lines = [
291
- # '| Name | Age |',
292
- # '| John | 30 |'
293
- # ]
294
- # expected_output = [
295
- # '| Name | Age |',
296
- # '| John | 30 |'
297
- # ]
298
- # assert_equal expected_output, MarkdownTableFormatter.format_table(
299
- # lines: lines,
300
- # column_count: 3
301
- # )
302
- # end
303
- # end
@@ -1,23 +0,0 @@
1
- require 'yaml'
2
- require 'terminal-table'
3
-
4
- cmd = 'aws ce get-cost-and-usage --time-period Start=2023-12-01,End=2023-12-31 --granularity MONTHLY --metrics "UnblendedCost" "UsageQuantity" --group-by Type=DIMENSION,Key=SERVICE'
5
-
6
- # Parse the YAML content
7
- text = system(cmd)
8
- data = YAML.load(text)
9
-
10
- # Extracting the relevant information
11
- services = data['ResultsByTime'][0]['Groups'].map do |group|
12
- service_name = group['Keys'][0]
13
- unblended_cost = "#{group['Metrics']['UnblendedCost']['Amount']} #{group['Metrics']['UnblendedCost']['Unit']}"
14
- usage_quantity = "#{group['Metrics']['UsageQuantity']['Amount']} #{group['Metrics']['UsageQuantity']['Unit']}"
15
- [service_name, unblended_cost, usage_quantity]
16
- end
17
-
18
- # Create a table
19
- table = Terminal::Table.new headings: ['Service', 'Unblended Cost', 'Usage Quantity'],
20
- rows: services
21
-
22
- # Output the table
23
- puts table
data/lib/doh.rb DELETED
@@ -1,190 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # encoding=utf-8
5
-
6
- class DOH < Hash
7
- # Initialize with an optional hash and a block
8
- def initialize(initial_hash = {}, &block)
9
- super() # Initialize the parent Hash
10
- self.merge!(initial_hash) # Merge the initial hash into the current hash
11
- self.default_proc = block if block_given?
12
- end
13
-
14
- # Override method_missing to pass undefined methods to the parent Hash
15
- def method_missing(method_name, *args, &block)
16
- # sc = caller[0].split; pp ['DOH.mm',method_name,sc[-1],sc[-2].split('/')[-1].split(':')[0..1].join(':')]
17
- if Hash.instance_methods.include?(method_name)
18
- super
19
- else
20
- raise NoMethodError, "undefined method `#{method_name}` for #{self}:#{self.class}"
21
- end
22
- end
23
-
24
- # Ensure respond_to_missing? is correctly implemented
25
- def respond_to_missing?(method_name, include_private = false)
26
- # sc = caller[0].split; pp ['DOH.rtm?',method_name,sc[-1],sc[-2].split('/')[-1].split(':')[0..1].join(':')]
27
- Hash.instance_methods.include?(method_name) || super
28
- end
29
- end
30
-
31
- # class DOH < Hash
32
- # # Initialize with an optional hash and a block
33
- # def initialize(initial_hash = {}, &block)
34
- # super() # Initialize the parent Hash
35
- # self.merge!(initial_hash) # Merge the initial hash into the current hash
36
- # self.default_proc = block if block_given?
37
- # end
38
-
39
- # # Override method_missing to pass undefined methods to the parent Hash
40
- # def method_missing(method_name, *args, &block)
41
- # # pp ['DOH.mm',method_name]
42
- # if self.respond_to?(method_name)
43
- # self.send(method_name, *args, &block)
44
- # else
45
- # super
46
- # end
47
- # end
48
-
49
- # # Ensure respond_to_missing? is correctly implemented
50
- # # pp ['DOH.rtm?',method_name]
51
-
52
- # def respond_to_missing?(method_name, include_private = false)
53
- # self.respond_to?(method_name) || super
54
- # end
55
- # end
56
-
57
- # class LayeredHash
58
- # def initialize(table = {}, layers: %i[main])
59
- # @layers = layers.map { |layer| [layer, {}] }.to_h
60
- # @current_layer = layers.first
61
- # @layers[@current_layer] = table
62
- # end
63
-
64
- # private
65
-
66
- # def method_missing(method, *args, &block)
67
- # method_name = method.to_s
68
- # if @layers.respond_to?(method_name)
69
- # @layers.send(method_name, *args, &block)
70
- # elsif method_name[-1] == '='
71
- # @layers[method_name.chop.to_sym] = args[0]
72
- # elsif @layers.respond_to?(method_name)
73
- # @layers.send(method_name, *args)
74
- # else
75
- # @layers[method_name.to_sym]
76
- # end
77
- # rescue StandardError => err
78
- # warn("ERROR ** LayeredHash.method_missing(method: #{method_name}," \
79
- # " *args: #{args.inspect}, &block)")
80
- # warn err.inspect
81
- # warn(caller[0..4])
82
- # raise err
83
- # end
84
-
85
- # public
86
-
87
- # # Retrieves the value of a key from the current layer using hash notation
88
- # def [](key)
89
- # raise "Current layer not set" unless @current_layer
90
-
91
- # get_from_layer(@current_layer, key)
92
- # end
93
-
94
- # # Sets a key-value pair in the current layer using hash notation
95
- # def []=(key, value)
96
- # raise "Current layer not set" unless @current_layer
97
-
98
- # set(@current_layer, key, value)
99
- # end
100
-
101
- # def fetch(key, *args)
102
- # key_sym = key.to_sym
103
- # if respond_to?("get_#{key}")
104
- # send("get_#{key}")
105
- # # elsif @table.key?(key_sym)
106
- # elsif @layers[@current_layer].key?(key_sym)
107
- # # @table[key_sym]
108
- # @layers[@current_layer][key_sym]
109
- # elsif block_given?
110
- # yield key_sym
111
- # elsif args.count.positive?
112
- # # binding.irb
113
- # args.first
114
- # else
115
- # binding.irb
116
- # raise KeyError, "key not found: #{key}"
117
- # end.tap{|ret| pp([__LINE__,"Poly.fetch #{key} #{args}",'->',ret]) if $pd }
118
- # end
119
-
120
- # # Retrieves the value of a key from the highest priority layer that has a value
121
- # def get(key)
122
- # @layers.reverse_each do |_, hash|
123
- # return hash[key] if hash.key?(key)
124
- # end
125
- # nil
126
- # end
127
-
128
- # # Retrieves the value of a key from the specified layer
129
- # def get_from_layer(layer, key)
130
- # if @layers.key?(layer)
131
- # @layers[layer][key]
132
- # else
133
- # raise ArgumentError, "Layer #{layer} does not exist"
134
- # end
135
- # end
136
-
137
- # def merge(*args)
138
- # @layers.merge(*args).tap{|ret| pp([__LINE__,"LayeredHash.merge",'->',ret]) if $pd }
139
- # end
140
-
141
- # def respond_to_missing?(method_name, include_private = false)
142
- # @layers.key?(method_name.to_sym) || super
143
- # end
144
-
145
- # # Sets a key-value pair in the specified layer
146
- # def set(layer, key, value)
147
- # if @layers.key?(layer)
148
- # @layers[layer][key] = value
149
- # else
150
- # raise ArgumentError, "Layer #{layer} does not exist"
151
- # end
152
- # end
153
-
154
- # # Sets the current layer for use with hash notation ([])
155
- # def set_current_layer(layer)
156
- # if @layers.key?(layer)
157
- # @current_layer = layer
158
- # else
159
- # raise ArgumentError, "Layer #{layer} does not exist"
160
- # end
161
- # end
162
-
163
- # def to_h
164
- # @layers.to_h
165
- # end
166
- # end
167
-
168
- return if $PROGRAM_NAME != __FILE__
169
-
170
- # layered_hash = LayeredHash.new(layers: %i[low high])
171
-
172
- # # Set current layer
173
- # layered_hash.set_current_layer(:low)
174
-
175
- # # Set values in the current layer using hash notation
176
- # layered_hash[:key1] = 'low_value'
177
- # layered_hash[:key2] = 'low_only_value'
178
-
179
- # # Switch current layer
180
- # layered_hash.set_current_layer(:high)
181
-
182
- # # Set values in the new current layer using hash notation
183
- # layered_hash[:key1] = 'high_value'
184
-
185
- # # Get value from the specific current layer using hash notation
186
- # puts layered_hash[:key1] # Output: 'high_value'
187
-
188
- # # Get value from the highest priority layer
189
- # puts layered_hash.get(:key1) # Output: 'high_value'
190
- # puts layered_hash.get(:key2) # Output: 'low_only_value'
data/lib/layered_hash.rb DELETED
@@ -1,143 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- # encoding=utf-8
5
-
6
- class LayeredHash
7
- def initialize(table = {}, layers: %i[main])
8
- @layers = layers.map { |layer| [layer, {}] }.to_h
9
- @current_layer = layers.first
10
- @layers[@current_layer] = table
11
- end
12
-
13
- private
14
-
15
- def method_missing(method, *args, &block)
16
- method_name = method.to_s
17
- if @layers.respond_to?(method_name)
18
- @layers.send(method_name, *args, &block)
19
- elsif method_name[-1] == '='
20
- @layers[method_name.chop.to_sym] = args[0]
21
- elsif @layers.respond_to?(method_name)
22
- @layers.send(method_name, *args)
23
- else
24
- @layers[method_name.to_sym]
25
- end
26
- rescue StandardError => err
27
- warn("ERROR ** LayeredHash.method_missing(method: #{method_name}," \
28
- " *args: #{args.inspect}, &block)")
29
- warn err.inspect
30
- warn(caller[0..4])
31
- raise err
32
- end
33
-
34
- public
35
-
36
- # Retrieves the value of a key from the current layer using hash notation
37
- def [](key)
38
- raise "Current layer not set" unless @current_layer
39
-
40
- get_from_layer(@current_layer, key)
41
- end
42
-
43
- # Sets a key-value pair in the current layer using hash notation
44
- def []=(key, value)
45
- raise "Current layer not set" unless @current_layer
46
-
47
- set(@current_layer, key, value)
48
- end
49
-
50
- def fetch(key, *args)
51
- key_sym = key.to_sym
52
- if respond_to?("get_#{key}")
53
- send("get_#{key}")
54
- # elsif @table.key?(key_sym)
55
- elsif @layers[@current_layer].key?(key_sym)
56
- # @table[key_sym]
57
- @layers[@current_layer][key_sym]
58
- elsif block_given?
59
- yield key_sym
60
- elsif args.count.positive?
61
- args.first
62
- else
63
- binding.irb
64
- raise KeyError, "key not found: #{key}"
65
- end.tap { |ret|
66
- pp([__LINE__, "Poly.fetch #{key} #{args}", '->',
67
- ret]) if $pd
68
- }
69
- end
70
-
71
- # Retrieves the value of a key from the highest priority layer that has a value
72
- def get(key)
73
- @layers.reverse_each do |_, hash|
74
- return hash[key] if hash.key?(key)
75
- end
76
- nil
77
- end
78
-
79
- # Retrieves the value of a key from the specified layer
80
- def get_from_layer(layer, key)
81
- if @layers.key?(layer)
82
- @layers[layer][key]
83
- else
84
- raise ArgumentError, "Layer #{layer} does not exist"
85
- end
86
- end
87
-
88
- def merge(*args)
89
- @layers.merge(*args).tap { |ret|
90
- pp([__LINE__, "LayeredHash.merge", '->', ret]) if $pd
91
- }
92
- end
93
-
94
- def respond_to_missing?(method_name, include_private = false)
95
- @layers.key?(method_name.to_sym) || super
96
- end
97
-
98
- # Sets a key-value pair in the specified layer
99
- def set(layer, key, value)
100
- if @layers.key?(layer)
101
- @layers[layer][key] = value
102
- else
103
- raise ArgumentError, "Layer #{layer} does not exist"
104
- end
105
- end
106
-
107
- # Sets the current layer for use with hash notation ([])
108
- def set_current_layer(layer)
109
- if @layers.key?(layer)
110
- @current_layer = layer
111
- else
112
- raise ArgumentError, "Layer #{layer} does not exist"
113
- end
114
- end
115
-
116
- def to_h
117
- @layers.to_h
118
- end
119
- end
120
-
121
- return if $PROGRAM_NAME != __FILE__
122
-
123
- layered_hash = LayeredHash.new(layers: %i[low high])
124
-
125
- # Set current layer
126
- layered_hash.set_current_layer(:low)
127
-
128
- # Set values in the current layer using hash notation
129
- layered_hash[:key1] = 'low_value'
130
- layered_hash[:key2] = 'low_only_value'
131
-
132
- # Switch current layer
133
- layered_hash.set_current_layer(:high)
134
-
135
- # Set values in the new current layer using hash notation
136
- layered_hash[:key1] = 'high_value'
137
-
138
- # Get value from the specific current layer using hash notation
139
- puts layered_hash[:key1] # Output: 'high_value'
140
-
141
- # Get value from the highest priority layer
142
- puts layered_hash.get(:key1) # Output: 'high_value'
143
- puts layered_hash.get(:key2) # Output: 'low_only_value'