Class: Spec::Fixture::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/spec/fixture/base.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(binding, hash, &block) ⇒ Base

Returns a new instance of Base.



4
5
6
7
8
9
10
11
12
13
14
15
# File 'lib/spec/fixture/base.rb', line 4

def initialize binding, hash, &block
  @binding = binding
  input_names, expected_names = *hash.to_a.first
  unless input_names.kind_of? Array
    input_names = [ input_names ]
  end
  unless expected_names.kind_of? Array
    expected_names = [ expected_names ]
  end
  _define_fixture(input_names, expected_names)
  instance_eval(&block)
end

Instance Attribute Details

#desc_templateObject (readonly)

Returns the value of attribute desc_template.



2
3
4
# File 'lib/spec/fixture/base.rb', line 2

def desc_template
  @desc_template
end

#example_shared_runnerObject (readonly)

Returns the value of attribute example_shared_runner.



2
3
4
# File 'lib/spec/fixture/base.rb', line 2

def example_shared_runner
  @example_shared_runner
end

#fixturesObject (readonly)

Returns the value of attribute fixtures.



2
3
4
# File 'lib/spec/fixture/base.rb', line 2

def fixtures
  @fixtures
end

Instance Method Details

#_define_fixture(__input, __expected) ⇒ Object

generate temp class for fixture.



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
187
188
# File 'lib/spec/fixture/base.rb', line 121

def _define_fixture __input, __expected #:nodoc:
  klass = Class.new
  klass.class_eval do
    attr_reader :filter_of, :value_of, :msg

    define_method :initialize do |_input, _expected, msg, filter_of|
      @value_of = {}
      @filter_of = filter_of ? filter_of : {}
      [ [__input, _input], [__expected, _expected] ].each do |input_or_expected|
        if input_or_expected.first.size == 1
          key = input_or_expected.first.first
          @value_of[key] = input_or_expected.last
        else
          input_or_expected.first.zip(input_or_expected.last) do |key, value|
            @value_of[key] = value
          end
        end
      end
      @msg = msg
    end

    define_method :_members do
      [ __input, __expected].flatten
    end

    [ [__input, :_input], [__expected, :_expected] ].each do |input_or_expected|
      define_method input_or_expected.last do
        if input_or_expected.first.size == 1
          __send__(input_or_expected.first.first)
        else
          result_of = {}
          input_or_expected.first.each do |item|
            result_of[item] = __send__ item
          end

          result_of
        end
      end
    end

    [ __input, __expected ].flatten.each do |item|
      raise NameError if instance_methods.map{|i| i.to_s }.include? item.to_s

      define_method item do
        result = @value_of[item]
        if @filter_of[item].kind_of? Proc
          result = @filter_of[item].call(result)
        else
          if @filter_of[item]
            [ @filter_of[item] ].flatten.each do |filter|
              # XXX: Proc filter can not use in Array. 
              # It's simple, it think, do all in a proc.
              if filter.to_s =~ /^\./
                result = Spec::Fixture::Filter.__send__(filter.to_s.sub(/^\./, ''), result)
              else
                result = result.__send__ filter
              end
            end
          end
        end

        result
      end
    end
  end

  @class = klass
end

#desc_filters(hash) ⇒ Object

If you customize specify for example, you should use this method. This methods’s usage is the same as filters.



60
61
62
# File 'lib/spec/fixture/base.rb', line 60

def desc_filters hash
  @desc_filter_of = hash
end

#filters(hash) ⇒ Object

If you specify filters, you can use filtered value in it‘s block filters argument is hash that has a key of members. value should be string or symbol or Array that contain strings or symbols or Proc. In case value is Proc, filtered value is Proc’s result. In case value is Array, each item applyed by following rule. In case item is String that start from “.”, for example “.uri”, filter use Spec::Fixture::Filter module_functions Otherwise, Object#__send__ was applyed. If it has only a filter, you can omit bracket and applyed following above.



54
55
56
# File 'lib/spec/fixture/base.rb', line 54

def filters hash
  @filter_of = hash
end

#generate_msg(fxt, desc_template) ⇒ Object

:nodoc:



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
# File 'lib/spec/fixture/base.rb', line 64

def generate_msg fxt, desc_template #:nodoc:
  if desc_template
    msg = desc_template
    [ fxt._members, :msg ].flatten.each do |item|
      if item == :msg
        result = fxt.msg.to_s
      else
        result = fxt.value_of[item]
        if instance_variable_defined?('@desc_filter_of') && @desc_filter_of && @desc_filter_of[item]
          if @desc_filter_of[item].kind_of? Proc
            result = @desc_filter_of[item].call(result)
          else
            [ @desc_filter_of[item] ].flatten.each do |filter|
              # XXX: Proc filter can not use in Array. 
              # It's simple, it think, do all in a proc.
              if filter.to_s =~ /^\./
                result = Spec::Fixture::Filter.__send__(filter.to_s.sub(/^\./, ''), result)
              else
                result = result.__send__ filter
              end
            end
          end
        else
          result = result.inspect
        end
      end
      msg = msg.gsub(/:#{item.to_s}/, result)
    end

    msg
  else
    if fxt.msg
      fxt.msg
    else
      nil
    end
  end
end

#it(desc = nil, &example) ⇒ Object

This &example block was iterate as example by each fixture. when you specify description for example, you can use “:” started string as template variable. Template variable is expand to raw value’s inspect in default expect for :msg. If you customize output message, please use desc_filters.

Block should take argumentes in order input, expected. input and expected was a Hash in input has two or larger members. When input and expected has only a member, input has filtered value.



27
28
29
30
31
32
# File 'lib/spec/fixture/base.rb', line 27

def it desc=nil, &example
  @desc_template ||= []
  @desc_template << desc
  @example_shared_runner ||= []
  @example_shared_runner << example
end

#runObject

:nodoc:



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/spec/fixture/base.rb', line 103

def run #:nodoc:
  fixture = self
  desc_template = @desc_template
  @binding.module_eval do
    if fixture.fixtures
      fixture.fixtures.each do |fxt|
        fixture.example_shared_runner.sort_by { rand }.each_with_index do |runner,index|
          msg = fixture.generate_msg(fxt, desc_template.nil? ? nil : desc_template[index] )
          it msg do
            runner.call(fxt._input, fxt._expected)
          end
        end
      end
    end
  end
end

#set_fixtures(data) ⇒ Object

You specify test data in this methods. Argument should be Array that has a Hash (and string optionaly). In Hasy key, you write input data and in its value you write expected data.



37
38
39
40
41
42
43
44
# File 'lib/spec/fixture/base.rb', line 37

def set_fixtures data
  @fixtures = data.map do |item|
    fxt, msg = *item
    input, expected = *fxt.to_a.first
    filter_of = instance_variable_defined?('@filter_of') ? @filter_of : nil
    @class.new input, expected, msg, filter_of
  end.sort_by { rand } # you should write test to pass without order dependency.
end