Module: DevDoc::Test::PseudoI18nCrawler::ClassMethods

Defined in:
lib/dev_doc/test/pseudo_i18n_crawler.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#hitsObject

{ url => [ "[key] value", ... ] }



121
122
123
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 121

def hits
  @hits
end

Instance Method Details

#collect_strings(node, set) ⇒ Object



174
175
176
177
178
179
180
181
182
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 174

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?
  end
end

#diagObject



184
185
186
187
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 184

def diag
  "wrapped(localized via t)=#{@wrapped || 0}  data-sourced(fixtures, skipped)=#{@data_sourced || 0}  " \
    "unwrapped(candidates)=#{@unwrapped || 0}"
end

#fixture_dirObject

Directory of the fixtures scanned to filter out AR display values.



124
125
126
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 124

def fixture_dir
  @fixture_dir ||= ::Rails.root.join('test/fixtures').to_s
end

#fixture_stringsObject

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.



165
166
167
168
169
170
171
172
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 165

def fixture_strings
  @fixture_strings ||= Dir[File.join(fixture_dir, '**', '*.yml')].each_with_object(Set.new) do |file, set|
    data = YAML.safe_load(File.read(file), permitted_classes: [Date, Time], aliases: true)
    collect_strings(data, set)
  rescue Psych::Exception
    next
  end
end

#report_dirObject

Where per-role reports are written.



129
130
131
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 129

def report_dir
  @report_dir ||= ::Rails.root.join('test/integration/pseudo_i18n_crawler_test_results').to_s
end

#scan_body(url, body) ⇒ Object



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 133

def scan_body(url, body)
  return unless body.is_a?(String) && body.lstrip.start_with?('{', '[')

  json = begin
    JSON.parse(body)
  rescue JSON::ParserError
    return
  end

  walk(json) do |key, value|
    if value.include?(MARKER)
      @wrapped = (@wrapped || 0) + 1
    elsif trivial?(value)
      next
    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.
      @data_sourced = (@data_sourced || 0) + 1
    else
      @unwrapped = (@unwrapped || 0) + 1
      (hits[url] ||= []) << "[#{key}] #{value.inspect}"
    end
  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.

Returns:

  • (Boolean)


203
204
205
206
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 203

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



189
190
191
192
193
194
195
196
197
198
199
# File 'lib/dev_doc/test/pseudo_i18n_crawler.rb', line 189

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) }
  end
end