File: matcher.rb

package info (click to toggle)
ruby-generator-spec 0.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 180 kB
  • sloc: ruby: 610; makefile: 5
file content (171 lines) | stat: -rw-r--r-- 4,076 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
module GeneratorSpec
  module Matcher
    # Taken (with permission) from beard by Yahuda Katz
    # https://github.com/carlhuda/beard

    class File

      def description
        'file attributes and content'
      end

      def initialize(name, &block)
        @contents = []
        @name = name
        @negative_contents = []

        if block_given?
          instance_eval(&block)
        end
      end

      def contains(text)
        @contents << text
      end

      def does_not_contain(text)
        @negative_contents << text
      end

      def matches?(root)
        unless root.join(@name).exist?
          throw :failure, root.join(@name)
        end

        check_contents(root.join(@name))
      end

      protected

      def check_contents(file)
        contents = ::File.read(file)

        @contents.each do |string|
          unless contents.include?(string)
            throw :failure, [file, string, contents]
          end
        end

        @negative_contents.each do |string|
          if contents.include?(string)
            throw :failure, [:not, file, string, contents]
          end
        end
      end
    end

    class Migration < File
      def description
        'valid migration file'
      end

      def matches?(root)
        file_name = migration_file_name(root, @name)

        unless file_name && file_name.exist?
          throw :failure, @name
        end

        check_contents(file_name)
      end

      protected

      def migration_file_name(root, name) #:nodoc:
        directory, file_name = ::File.dirname(root.join(name)), ::File.basename(name).sub(/\.rb$/, '')
        migration = Dir.glob("#{directory}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
        Pathname.new(migration) if migration
      end
    end

    class Directory
      attr_reader :tree

      def description
        'has directory structure'
      end

      def initialize(root = nil, &block)
        @tree = {}
        @negative_tree = []
        @root = root
        instance_eval(&block) if block_given?
      end

      def directory(name, &block)
        @tree[name] = block_given? && Directory.new(location(name), &block)
      end

      def file(name, &block)
        @tree[name] = File.new(location(name), &block)
      end

      def no_file(name)
        @negative_tree << name
      end

      def location(name)
        [@root, name].compact.join("/")
      end

      def migration(name, &block)
        @tree[name] = Migration.new(location(name), &block)
      end

      def matches?(root)
        @tree.each do |file, value|
          unless value
            unless root.join(location(file)).exist?
              throw :failure, "#{root}/#{location(file)}"
            end
          else
            value.matches?(root)
          end
        end

        @negative_tree.each do |file|
          if root.join(location(file)).exist?
            throw :failure, [:not, "unexpected #{root}/#{location(file)}"]
          end
        end

        nil
      end
    end

    class Root < Directory
      def description
        'have specified directory structure'
      end

      def failure_message
        if @failure.is_a?(Array) && @failure[0] == :not
          if @failure.length > 2
            "Structure should have #{@failure[1]} without #{@failure[2]}. It had:\n#{@failure[3]}"
          else
            "Structure should not have had #{@failure[1]}, but it did"
          end
        elsif @failure.is_a?(Array)
          "Structure should have #{@failure[0]} with #{@failure[1]}. It had:\n#{@failure[2]}"
        else
          "Structure should have #{@failure}, but it didn't"
        end
      end

      def matches?(root)
        root = Pathname.new(root) unless root.is_a?(Pathname)
        @failure = catch :failure do
          super
        end

        !@failure
      end
    end

    def have_structure(&block)
      error = 'You must pass a block to have_structure (Use {} instead of do/end!)'
      raise RuntimeError, error unless block_given?
      Root.new(&block)
    end
  end
end