lib/scryglass/ro.rb in scryglass-1.1.0 vs lib/scryglass/ro.rb in scryglass-2.0.0

- old
+ new

@@ -41,18 +41,26 @@ ## Open up ViewWrappers and grab their objects and their custom strings if key.class == Scryglass::ViewWrapper self.key_string = key.to_s.clip_at(key_clip_length) self.key = key.model else - self.key_string = key.inspect.clip_at(key_clip_length) + # Note: `.inspect` may return *true newlines* for objects with a custom + # `.inspect`, which will sabotage scry's display, so we gsub thusly: + self.key_string = key.inspect + .gsub("\n", "\\n") + .clip_at(key_clip_length) self.key = key end if val.class == Scryglass::ViewWrapper self.value_string = val.to_s.clip_at(value_clip_length) self.value = val.model else - self.value_string = val.inspect.clip_at(value_clip_length) + # Note: `.inspect` may return *true newlines* for objects with a custom + # `.inspect`, which will sabotage scry's display, so we gsub thusly: + self.value_string = val.inspect + .gsub("\n", "\\n") + .clip_at(value_clip_length) self.value = val end self.sub_ros = [] self.parent_ro = parent_ro @@ -76,13 +84,14 @@ value_indicator = bucket? ? bucket_indicator : value_string key_value_spacer = key_value_pair? ? key_string + key_value_relationship_indicator : '' - + dot = '•' + dot = "\e[36m#{dot}\e[00m" if Scryglass.config.dot_coloring # cyan then back to *default* special_sub_ro_expansion_indicator = - special_sub_ros.any? && !expanded ? '•' : ' ' + special_sub_ros.any? && !expanded ? dot : ' ' left_fill_string + special_sub_ro_expansion_indicator + key_value_spacer + value_indicator end @@ -166,16 +175,16 @@ def key_value_pair? !!key_value_relationship_indicator end - private - def special_sub_ros sub_ros.select(&:special_sub_ro_type) end + private + def normal_sub_ros sub_ros.reject(&:special_sub_ro_type) end def bucket_indicator @@ -185,11 +194,13 @@ # Number of dots indicating order of magnitude for Enumerable's count: # Turning this off (the consistent three dots is more like an ellipsis, # communicating with a solid preexisting symbol), but keeping the idea here: # sub_ros_order_of_magnitude = normal_sub_ros.count.to_s.length # wrappers.dup.insert(1, '•' * sub_ros_order_of_magnitude) - wrappers.dup.insert(1, '•••') + dots = '•••' + dots = "\e[36m#{dots}\e[00m" if Scryglass.config.dot_coloring # cyan then back to *default* + wrappers.dup.insert(1, dots) else wrappers end end @@ -212,22 +223,80 @@ consistent_margin = [4 - tab_length, 0].max (tab_length * depth) + consistent_margin end + def cursor_char + Scryglass::Session::CURSOR_CHARACTER + end + def cursor_string - cursor = Scryglass::Session::CURSOR_CHARACTER * cursor_length + cursor = cursor_char * cursor_length - if nugget? && has_cursor && value.is_a?(Enumerable) && - value.any? && - enum_sub_ros.empty? - cursor[0] = '(' + cursor[0] = enum_status_char + cursor[1] = iv_status_char + cursor[2] = ar_status_char + + cursor + end + + def enum_status_char + enum_worth_checking = nugget? && value.is_a?(Enumerable) + return cursor_char unless enum_worth_checking + + enum_check = Scryglass::Ro.safe_quick_check do + # value.any? Can take an eternity for a few specific objects, breaking + # the session when the cursor passes over them. Also breaks on read- + # locked IO objects. + enum_sub_ros.empty? && value.any? end - if value.instance_variables.any? && iv_sub_ros.empty? - cursor[1] = '@' + return 'X' if enum_check.nil? + + return '(' if enum_check + + cursor_char + end + + def iv_status_char + return cursor_char unless iv_sub_ros.empty? + + iv_check = Scryglass::Ro.safe_quick_check do + value.instance_variables.any? end - cursor + return 'X' if iv_check.nil? + + return '@' if iv_check + + cursor_char + end + + def ar_status_char + return cursor_char unless ar_sub_ros.empty? + + iv_check = Scryglass::Ro.safe_quick_check do + # Currently, this will always indicate hidden secrets if the object, with + # the given Scryglass config, doesn't yield any ar_sub_ros upon trying '.' + value.class.respond_to?(:reflections) # TODO: maybe dig more here? + end + + return 'X' if iv_check.nil? + + return '·' if iv_check + + cursor_char + end + + class << self + def safe_quick_check + begin + Timeout.timeout(0.05) do + yield + end + rescue + nil + end + end end end end