File: object_formatter.rb

package info (click to toggle)
ruby-rspec 3.4.0c3e0m1s1-1~bpo8%2B1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-backports
  • size: 6,124 kB
  • sloc: ruby: 59,418; sh: 1,405; makefile: 98
file content (108 lines) | stat: -rw-r--r-- 3,307 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
55
56
57
58
59
60
61
62
63
64
65
66
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
module RSpec
  module Support
    # Provide additional output details beyond what `inspect` provides when
    # printing Time, DateTime, or BigDecimal
    module ObjectFormatter
      # @api private
      def self.format(object)
        prepare_for_inspection(object).inspect
      end

      # rubocop:disable MethodLength

      # @private
      # Prepares the provided object to be formatted by wrapping it as needed
      # in something that, when `inspect` is called on it, will produce the
      # desired output.
      #
      # This allows us to apply the desired formatting to hash/array data structures
      # at any level of nesting, simply by walking that structure and replacing items
      # with custom items that have `inspect` defined to return the desired output
      # for that item. Then we can just use `Array#inspect` or `Hash#inspect` to
      # format the entire thing.
      def self.prepare_for_inspection(object)
        case object
        when Array
          return object.map { |o| prepare_for_inspection(o) }
        when Hash
          return prepare_hash(object)
        when Time
          inspection = format_time(object)
        else
          if defined?(DateTime) && DateTime === object
            inspection = format_date_time(object)
          elsif defined?(BigDecimal) && BigDecimal === object
            inspection = "#{object.to_s 'F'} (#{object.inspect})"
          elsif RSpec::Support.is_a_matcher?(object) && object.respond_to?(:description)
            inspection = object.description
          else
            return DelegatingInspector.new(object)
          end
        end

        InspectableItem.new(inspection)
      end
      # rubocop:enable MethodLength

      # @private
      def self.prepare_hash(input)
        input.inject({}) do |hash, (k, v)|
          hash[prepare_for_inspection(k)] = prepare_for_inspection(v)
          hash
        end
      end

      TIME_FORMAT = "%Y-%m-%d %H:%M:%S"

      if Time.method_defined?(:nsec)
        # @private
        def self.format_time(time)
          time.strftime("#{TIME_FORMAT}.#{"%09d" % time.nsec} %z")
        end
      else # for 1.8.7
        # @private
        def self.format_time(time)
          time.strftime("#{TIME_FORMAT}.#{"%06d" % time.usec} %z")
        end
      end

      DATE_TIME_FORMAT = "%a, %d %b %Y %H:%M:%S.%N %z"
      # ActiveSupport sometimes overrides inspect. If `ActiveSupport` is
      # defined use a custom format string that includes more time precision.
      # @private
      def self.format_date_time(date_time)
        if defined?(ActiveSupport)
          date_time.strftime(DATE_TIME_FORMAT)
        else
          date_time.inspect
        end
      end

      # @private
      InspectableItem = Struct.new(:inspection) do
        def inspect
          inspection
        end

        def pretty_print(pp)
          pp.text inspection
        end
      end

      # @private
      DelegatingInspector = Struct.new(:object) do
        def inspect
          if defined?(::Delegator) && ::Delegator === object
            "#<#{object.class}(#{ObjectFormatter.format(object.__getobj__)})>"
          else
            object.inspect
          end
        end

        def pretty_print(pp)
          pp.text inspect
        end
      end
    end
  end
end