File: location.rb

package info (click to toggle)
ruby-cucumber-core 16.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 764 kB
  • sloc: ruby: 5,074; makefile: 2
file content (186 lines) | stat: -rw-r--r-- 4,045 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# frozen_string_literal: true

require 'forwardable'
require 'cucumber/core/platform'
require 'set'

module Cucumber
  module Core
    module Test
      IncompatibleLocations = Class.new(StandardError)

      module Location
        def self.of_caller(additional_depth = 0)
          from_file_colon_line(*caller[1 + additional_depth])
        end

        def self.from_file_colon_line(file_colon_line)
          file, raw_line = file_colon_line.match(/(.*):(\d+)/)[1..2]
          from_source_location(file, raw_line.to_i)
        end

        def self.from_source_location(file, line, *_args)
          file = File.expand_path(file)
          pwd = File.expand_path(Dir.pwd)
          pwd.force_encoding(file.encoding)
          if file.index(pwd)
            file = file[(pwd.length + 1)..]
          elsif file.match?(/gems\/(.+\.rb)$/)
            file = file.split('gems/').last
          end
          new(file, line)
        end

        def self.new(file, raw_lines = nil)
          if raw_lines
            Precise.new(file, Lines.new(raw_lines))
          else
            Wildcard.new(file)
          end
        end

        Wildcard = Struct.new(:file) do
          def to_s
            file
          end

          def match?(other)
            other.file == file
          end

          def include?(_lines)
            true
          end
        end

        Precise = Struct.new(:file, :lines) do
          def include?(other_lines)
            lines.include?(other_lines)
          end

          def line
            lines.first
          end

          def match?(other)
            return false unless other.file == file

            other.include?(lines)
          end

          def to_s
            [file, lines.to_s].join(':')
          end

          def hash
            [self.class, to_s].hash
          end

          def to_str
            to_s
          end

          def merge(multiline_arg)
            new_lines = (0..multiline_arg.lines_count).map do |offset|
              lines.min + offset
            end
            Location.new(file, new_lines)
          end

          def on_line(new_line)
            Location.new(file, new_line)
          end

          def inspect
            "<#{self.class}: #{self}>"
          end
        end

        Lines = Struct.new(:data) do
          protected :data

          def initialize(raw_data)
            super(Array(raw_data).to_set)
          end

          def first
            data.first
          end

          def min
            data.min
          end

          def max
            data.max
          end

          def include?(other)
            other.data.subset?(data) || data.subset?(other.data)
          end

          def +(other)
            new_data = data + other.data
            self.class.new(new_data)
          end

          def to_s
            return first.to_s if data.length == 1
            return "#{data.min}..#{data.max}" if range?

            data.to_a.join(':')
          end

          def inspect
            "<#{self.class}: #{self}>"
          end

          protected

          def range?
            data.size == (data.max - data.min + 1)
          end
        end
      end

      module HasLocation
        def file_colon_line
          location.to_s
        end

        def file
          location.file
        end

        def line
          location.line
        end

        def location
          raise('Please set @location in the constructor') unless defined?(@location)

          @location
        end

        def attributes
          [tags, comments, multiline_arg].flatten
        end

        def tags
          # will be overridden by nodes that actually have tags
          []
        end

        def comments
          # will be overridden by nodes that actually have comments
          []
        end

        def multiline_arg
          # will be overridden by nodes that actually have a multiline_argument
          Test::EmptyMultilineArgument.new
        end
      end
    end
  end
end