Class: CachedNestedFileReader
- Includes:
- Exceptions
- Defined in:
- lib/cached_nested_file_reader.rb
Overview
The CachedNestedFileReader class provides functionality to read file lines with the ability to process ‘#import filename’ directives. When such a directive is encountered in a file, the corresponding ‘filename’ is read and its contents are inserted at that location. This class caches read files to avoid re-reading the same file multiple times. It allows clients to read lines with or without providing a block.
Instance Method Summary collapse
- #error_handler(name = '', opts = {}) ⇒ Object
-
#initialize(import_directive_line_pattern:, import_directive_parameter_scan:, import_parameter_variable_assignment:, shell:, shell_block_name:, symbol_command_substitution:, symbol_evaluated_expression:, symbol_force_quoted_literal:, symbol_raw_literal:, symbol_variable_reference:) ⇒ CachedNestedFileReader
constructor
A new instance of CachedNestedFileReader.
-
#readlines(filename, depth = 0, context: '', import_paths: nil, indention: '', substitutions: {}, use_template_delimiters: false, clear_cache: true, read_cache: false, &block) ⇒ Object
yield each line to the block return the processed lines.
- #warn_format(name, message, opts = {}) ⇒ Object
Methods included from Exceptions
Constructor Details
#initialize(import_directive_line_pattern:, import_directive_parameter_scan:, import_parameter_variable_assignment:, shell:, shell_block_name:, symbol_command_substitution:, symbol_evaluated_expression:, symbol_force_quoted_literal:, symbol_raw_literal:, symbol_variable_reference:) ⇒ CachedNestedFileReader
Returns a new instance of CachedNestedFileReader.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/cached_nested_file_reader.rb', line 26 def initialize( import_directive_line_pattern:, import_directive_parameter_scan:, import_parameter_variable_assignment:, shell:, shell_block_name:, symbol_command_substitution:, symbol_evaluated_expression:, symbol_force_quoted_literal:, symbol_raw_literal:, symbol_variable_reference: ) @file_cache = {} @import_directive_line_pattern = import_directive_line_pattern @import_directive_parameter_scan = import_directive_parameter_scan @import_parameter_variable_assignment = import_parameter_variable_assignment @shell = shell @shell_block_name = shell_block_name @symbol_command_substitution = symbol_command_substitution @symbol_evaluated_expression = symbol_evaluated_expression @symbol_force_quoted_literal = symbol_force_quoted_literal @symbol_raw_literal = symbol_raw_literal @symbol_variable_reference = symbol_variable_reference end |
Instance Method Details
#error_handler(name = '', opts = {}) ⇒ Object
51 52 53 54 55 56 |
# File 'lib/cached_nested_file_reader.rb', line 51 def error_handler(name = '', opts = {}) Exceptions.error_handler( "CachedNestedFileReader.#{name} -- #{$!}", opts ) end |
#readlines(filename, depth = 0, context: '', import_paths: nil, indention: '', substitutions: {}, use_template_delimiters: false, clear_cache: true, read_cache: false, &block) ⇒ Object
yield each line to the block return the processed lines
67 68 69 70 71 72 73 74 75 76 77 78 79 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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/cached_nested_file_reader.rb', line 67 def readlines( filename, depth = 0, context: '', import_paths: nil, indention: '', substitutions: {}, use_template_delimiters: false, clear_cache: true, read_cache: false, &block ) # clear cache if requested @file_cache.clear if clear_cache cache_key = build_cache_key(filename, substitutions) if @file_cache.key?(cache_key) return ["# dup #{cache_key}"] unless read_cache @file_cache[cache_key].each(&block) if block return @file_cache[cache_key] # do not return duplicates per filename and substitutions # return an indicator that the file was already read end raise Errno::ENOENT, filename unless filename directory_path = File.dirname(filename) processed_lines = [] continued_line = nil # continued import directive File.readlines(filename, chomp: true).each.with_index do |segment, ind| wwt :readline, 'depth:', depth, 'filename:', filename, 'ind:', ind, 'segment:', segment if continued_line || (Regexp.new(@import_directive_line_pattern) =~ segment) line = (continued_line || '') + segment # if segment ends in a continuation, prepend to next line if line.end_with?('\\') continued_line = line.chomp('\\') next end continued_line = nil # apply substitutions to the @import line line_sub1 = apply_line_substitutions(line, substitutions, use_template_delimiters) # parse the @import line Regexp.new(@import_directive_line_pattern) =~ line_sub1 name_strip = $~[:name].strip params_string = $~[:params] || '' import_indention = indention + $~[:indention] # Parse parameters for text substitution import_substitutions, add_code = parse_import_params(params_string) if add_code # strings as NestedLines add_lines = add_code.map.with_index do |line2, ind2| nested_line = NestedLine.new( line2, depth + 1, import_indention, filename, ind2 ) block&.call(nested_line) nested_line end ww 'add_lines:', add_lines processed_lines += add_lines end merged_substitutions = substitutions.merge(import_substitutions) included_file_path = if name_strip =~ %r{^/} name_strip elsif import_paths find_files(name_strip, import_paths + [directory_path])&.first else File.join(directory_path, name_strip) end raise Errno::ENOENT, name_strip unless included_file_path # Create a cache key for the imported file that includes both filename and parameters imported_cache_key = build_import_cache_key(included_file_path, name_strip, params_string, merged_substitutions) # Check if we've already loaded this specific import if @file_cache.key?(imported_cache_key) imported_lines = @file_cache[imported_cache_key] else imported_lines = readlines( included_file_path, depth + 1, context: "#{filename}:#{ind + 1}", import_paths: import_paths, indention: import_indention, substitutions: merged_substitutions, use_template_delimiters: use_template_delimiters, clear_cache: false, &block ) # Cache the imported lines with the specific import cache key @file_cache[imported_cache_key] = imported_lines end # Apply text substitutions to imported content processed_imported_lines = apply_substitutions( imported_lines, import_substitutions, use_template_delimiters ) processed_lines += processed_imported_lines else # Apply substitutions to the current line substituted_line = apply_line_substitutions(segment, substitutions, use_template_delimiters) nested_line = NestedLine.new(substituted_line, depth, indention, filename, ind) processed_lines.push(nested_line) block&.call(nested_line) end end wwt :read_document_code, 'processed_lines:', processed_lines @file_cache[cache_key] = processed_lines rescue Errno::ENOENT => err warn_format('readlines', "#{err} @@ #{context}", { abort: true }) rescue StandardError wwe $! end |
#warn_format(name, message, opts = {}) ⇒ Object
58 59 60 61 62 63 |
# File 'lib/cached_nested_file_reader.rb', line 58 def warn_format(name, , opts = {}) Exceptions.warn_format( "CachedNestedFileReader.#{name} -- #{message}", opts ) end |