Module: AppMap::Util
- Defined in:
- lib/appmap/util.rb
Constant Summary collapse
- CLEAR =
wynnnetherland.com/journal/a-stylesheet-author-s-guide-to-terminal-colors/ Embed in a String to clear all previous ANSI sequences.
"\e[0m"- BOLD =
"\e[1m"- BLACK =
Colors
"\e[30m"- RED =
"\e[31m"- GREEN =
"\e[32m"- YELLOW =
"\e[33m"- BLUE =
"\e[34m"- MAGENTA =
"\e[35m"- CYAN =
"\e[36m"- WHITE =
"\e[37m"
Class Method Summary collapse
- .blank?(obj) ⇒ Boolean
- .classify(word) ⇒ Object
- .color(text, color, bold: false) ⇒ Object
- .deep_dup(hash) ⇒ Object
- .normalize_path(path) ⇒ Object
-
.sanitize_event(event, &block) ⇒ Object
sanitize_event removes ephemeral values from an event, making events easier to compare across runs.
-
.sanitize_paths(h) ⇒ Object
sanitize_paths removes ephemeral values from objects with embedded paths (e.g. an event or a classmap), making events easier to compare across runs.
-
.scenario_filename(name, max_length: 255, separator: '_', extension: '.appmap.json') ⇒ Object
scenario_filename builds a suitable file name from a scenario name.
- .select_headers(env) ⇒ Object
- .startup_message(msg) ⇒ Object
-
.swaggerize_path(path) ⇒ Object
Convert a Rails-style path from /org/:org_id(.:format) to Swagger-style paths like /org/org_id.
-
.write_appmap(filename, appmap) ⇒ Object
Atomically writes AppMap data to
filename.
Class Method Details
.blank?(obj) ⇒ Boolean
162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/appmap/util.rb', line 162 def blank?(obj) return true if obj.nil? return true if obj.is_a?(String) && obj == '' return true if obj.respond_to?(:length) && obj.length == 0 return true if obj.respond_to?(:size) && obj.size == 0 false end |
.classify(word) ⇒ Object
153 154 155 |
# File 'lib/appmap/util.rb', line 153 def classify(word) word.split(/[\-_]/).map(&:capitalize).join end |
.color(text, color, bold: false) ⇒ Object
147 148 149 150 151 |
# File 'lib/appmap/util.rb', line 147 def color(text, color, bold: false) color = Util.const_get(color.to_s.upcase) if color.is_a?(Symbol) bold = bold ? BOLD : "" "#{bold}#{color}#{text}#{CLEAR}" end |
.deep_dup(hash) ⇒ Object
157 158 159 160 |
# File 'lib/appmap/util.rb', line 157 def deep_dup(hash) # This is a simple way to avoid the need for deep_dup from activesupport. Marshal.load(Marshal.dump(hash)) end |
.normalize_path(path) ⇒ Object
113 114 115 116 117 118 119 |
# File 'lib/appmap/util.rb', line 113 def normalize_path(path) if path.index(Dir.pwd) == 0 && !path.index(Bundler.bundle_path.to_s) path[Dir.pwd.length + 1..-1] else path end end |
.sanitize_event(event, &block) ⇒ Object
sanitize_event removes ephemeral values from an event, making events easier to compare across runs.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/appmap/util.rb', line 75 def sanitize_event(event, &block) event.delete(:thread_id) event.delete(:elapsed) delete_object_id = ->(obj) { (obj || {}).delete(:object_id) } delete_object_id.call(event[:receiver]) delete_object_id.call(event[:return_value]) %i[parameters exceptions message].each do |field| (event[field] || []).each(&delete_object_id) end %i[http_client_request http_client_response http_server_request http_server_response].each do |field| headers = event.dig(field, :headers) next unless headers headers['Date'] = '<instanceof date>' if headers['Date'] headers['Server'] = headers['Server'].match(/^(\w+)/)[0] if headers['Server'] end case event[:event] when :call sanitize_paths(event) end event end |
.sanitize_paths(h) ⇒ Object
sanitize_paths removes ephemeral values from objects with embedded paths (e.g. an event or a classmap), making events easier to compare across runs.
59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/appmap/util.rb', line 59 def sanitize_paths(h) require 'hashie' h.extend(Hashie::Extensions::DeepLocate) keys = %i(path location) h.deep_locate ->(k,v,o) { next unless keys.include?(k) fix = ->(v) {v.gsub(%r{#{Gem.dir}/gems/.*(?=lib)}, '')} keys.each {|k| o[k] = fix.(o[k]) if o[k] } } h end |
.scenario_filename(name, max_length: 255, separator: '_', extension: '.appmap.json') ⇒ Object
scenario_filename builds a suitable file name from a scenario name. Special characters are removed, and the file name is truncated to fit within shell limitations.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/appmap/util.rb', line 26 def scenario_filename(name, max_length: 255, separator: '_', extension: '.appmap.json') # Cribbed from v5 version of ActiveSupport:Inflector#parameterize: # https://github.com/rails/rails/blob/v5.2.4/activesupport/lib/active_support/inflector/transliterate.rb#L92 # Replace accented chars with their ASCII equivalents. fname = name.encode('utf-8', invalid: :replace, undef: :replace, replace: '_') # Turn unwanted chars into the separator. fname.gsub!(/[^a-z0-9\-_]+/i, separator) re_sep = Regexp.escape(separator) re_duplicate_separator = /#{re_sep}{2,}/ re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i # No more than one of the separator in a row. fname.gsub!(re_duplicate_separator, separator) # Finally, Remove leading/trailing separator. fname.gsub!(re_leading_trailing_separator, '') if (fname.length + extension.length) > max_length require 'base64' require 'digest' fname_digest = Base64.urlsafe_encode64 Digest::MD5.digest(fname), padding: false fname[max_length - fname_digest.length - extension.length - 1..-1] = [ '-', fname_digest ].join end [ fname, extension ].join end |
.select_headers(env) ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/appmap/util.rb', line 100 def select_headers(env) # Rack prepends HTTP_ to all client-sent headers. matching_headers = env .select { |k,v| k.start_with? 'HTTP_'} .reject { |k,v| blank?(v) } .each_with_object({}) do |kv, memo| key = kv[0].sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-') value = kv[1] memo[key] = value end blank?(matching_headers) ? nil : matching_headers end |
.startup_message(msg) ⇒ Object
174 175 176 177 178 179 180 |
# File 'lib/appmap/util.rb', line 174 def (msg) if defined?(::Rails) && defined?(::Rails.logger) && ::Rails.logger ::Rails.logger.debug msg elsif ENV['DEBUG'] == 'true' warn msg end end |
.swaggerize_path(path) ⇒ Object
Convert a Rails-style path from /org/:org_id(.:format) to Swagger-style paths like /org/org_id
123 124 125 126 127 128 129 |
# File 'lib/appmap/util.rb', line 123 def swaggerize_path(path) path = path.split('(.')[0] tokens = path.split('/') tokens.map do |token| token.gsub /^:(.*)/, '{\1}' end.join('/') end |
.write_appmap(filename, appmap) ⇒ Object
Atomically writes AppMap data to filename.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/appmap/util.rb', line 132 def write_appmap(filename, appmap) require 'fileutils' require 'tmpdir' # This is what Ruby Tempfile does; but we don't want the file to be unlinked. mode = File::RDWR | File::CREAT | File::EXCL ::Dir::Tmpname.create([ 'appmap_', '.json' ]) do |tmpname| tempfile = File.open(tmpname, mode) tempfile.write(appmap) tempfile.close # Atomically move the tempfile into place. FileUtils.mv tempfile.path, filename end end |