Module: DevDoc::Test::PseudoI18nCrawler::ClassMethods
- Defined in:
- lib/dev_doc/test/pseudo_i18n_crawler.rb
Overview
Per-run accumulator surface for the including test class.
Instance Attribute Summary collapse
-
#hits ⇒ Object
{ url => [ "[key] value", ... ] }.
Instance Method Summary collapse
- #collect_strings(node, set) ⇒ Object
-
#counters ⇒ Object
Per-run bucket counts for the DIAG line.
- #diag ⇒ Object
-
#fixture_dir ⇒ Object
Directory of the fixtures scanned to filter out AR display values.
-
#fixture_strings ⇒ Object
Verbatim string values from the fixtures.
- #parse_json(body) ⇒ Object
-
#report_dir ⇒ Object
Where per-role reports are written.
- #scan_body(url, body) ⇒ Object
-
#tally(url, key, value) ⇒ Object
Buckets one text-prop value: wrapped (went through t()), trivial (not copy), data-sourced (verbatim fixture string), or a hardcoded candidate recorded in
hits. -
#trivial?(str) ⇒ Boolean
Skip values that are not copy: blank, no letters (numbers/units/ symbols), or ALL_CAPS code identifiers.
- #walk(node, &blk) ⇒ Object
Instance Attribute Details
#hits ⇒ Object
{ url => [ "[key] value", ... ] }
111 112 113 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 111 def hits @hits end |
Instance Method Details
#collect_strings(node, set) ⇒ Object
177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 177 def collect_strings(node, set) case node when Hash then node.each_value { |v| collect_strings(v, set) } when Array then node.each { |v| collect_strings(v, set) } when String s = node.strip set << s unless s.empty? else # Non-string scalars (numbers, booleans, nil, dates) carry no copy. end end |
#counters ⇒ Object
Per-run bucket counts for the DIAG line.
157 158 159 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 157 def counters @counters ||= Hash.new(0) end |
#diag ⇒ Object
189 190 191 192 193 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 189 def diag "wrapped(localized via t)=#{counters[:wrapped]} " \ "data-sourced(fixtures, skipped)=#{counters[:data_sourced]} " \ "unwrapped(candidates)=#{counters[:unwrapped]}" end |
#fixture_dir ⇒ Object
Directory of the fixtures scanned to filter out AR display values.
114 115 116 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 114 def fixture_dir @fixture_dir ||= ::Rails.root.join('test/fixtures').to_s end |
#fixture_strings ⇒ Object
Verbatim string values from the fixtures. A candidate equal to one of these is an ActiveRecord display value (loaded from the DB, so it never went through t() by design) rather than hardcoded copy, and is excluded to cut the bulk of the AR noise. Exact match only — a hardcoded string that happens to equal a fixture value would be skipped too, an acceptable trade for ~85% less noise. Built once; fixtures contain no ERB so static YAML parsing is exact.
168 169 170 171 172 173 174 175 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 168 def fixture_strings @fixture_strings ||= Dir[File.join(fixture_dir, '**', '*.yml')].each_with_object(Set.new) do |file, set| data = YAML.safe_load_file(file, permitted_classes: [Date, Time], aliases: true) collect_strings(data, set) rescue Psych::Exception next end end |
#parse_json(body) ⇒ Object
123 124 125 126 127 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 123 def parse_json(body) JSON.parse(body) rescue JSON::ParserError nil end |
#report_dir ⇒ Object
Where per-role reports are written.
119 120 121 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 119 def report_dir @report_dir ||= ::Rails.root.join('test/integration/pseudo_i18n_crawler_test_results').to_s end |
#scan_body(url, body) ⇒ Object
129 130 131 132 133 134 135 136 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 129 def scan_body(url, body) return unless body.is_a?(String) && body.lstrip.start_with?('{', '[') json = parse_json(body) return unless json walk(json) { |key, value| tally(url, key, value) } end |
#tally(url, key, value) ⇒ Object
Buckets one text-prop value: wrapped (went through t()), trivial
(not copy), data-sourced (verbatim fixture string), or a hardcoded
candidate recorded in hits.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 141 def tally(url, key, value) if value.include?(MARKER) counters[:wrapped] += 1 elsif trivial?(value) nil elsif fixture_strings.include?(value.strip) # ActiveRecord display value (record title/name/user copy) that # came straight from the DB — data, not a hardcoded UI string. counters[:data_sourced] += 1 else counters[:unwrapped] += 1 (hits[url] ||= []) << "[#{key}] #{value.inspect}" end end |
#trivial?(str) ⇒ Boolean
Skip values that are not copy: blank, no letters (numbers/units/ symbols), or ALL_CAPS code identifiers. Tune as real noise surfaces.
212 213 214 215 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 212 def trivial?(str) s = str.strip s.empty? || !s.match?(/[A-Za-z]/) || s.match?(/\A[A-Z0-9_]+\z/) end |
#walk(node, &blk) ⇒ Object
195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 195 def walk(node, &blk) case node when Hash node.each do |k, v| blk.call(k, v) if TEXT_KEYS.include?(k) && v.is_a?(String) walk(v, &blk) end when Array node.each { |v| walk(v, &blk) } else # Scalars have no children to walk; string values are handed to # the block by their parent hash above. end end |