Class: MiniSpec::Proxy

Inherits:
Object
  • Object
show all
Defined in:
lib/minispec/proxy.rb

Constant Summary collapse

@@negations =
[
  :not,
  :to_not,
  :has_not,
  :have_not,
  :does_not,
  :did_not,
  :is_not,
  :is_not_a,
  :wont,
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(*args, &proc) ⇒ Proxy

initializes a new proxy instance that will forward all received messages to tested object.

Parameters:

  • base

    spec instance

  • left_method

    the method on spec instance that accepts tested object, eg: is(…), does(…) etc.

  • left_object

    tested object itself

  • negation

    if set to a positive value assertion will be marked as failed if passed

  • &proc

    if block given, it will be yielded(at a later point) and returned value will be used as tested object.



26
27
28
29
30
# File 'lib/minispec/proxy.rb', line 26

def initialize *args, &proc
  @base, @left_method, @left_object, @negation, @failure_message = args
  @left_proc = proc
  @sugar = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *a, &p) ⇒ Object

any missing method will be forwarded to #__ms__assert. simply returns if no spec instance set.

Examples:

checking whether ‘some_array` include `foo`

does(some_array).include? foo
# MiniSpec::Proxy instance does not respond to `include?`, so it is passed to `some_array`


53
54
55
# File 'lib/minispec/proxy.rb', line 53

def method_missing m, *a, &p
  @base && __ms__assert(m, *a, &p)
end

Instance Method Details

#__ms__assert(right_method, *args, &right_proc) ⇒ Object

the core of MiniSpec assertion methodology. all tested objects arrives this point where they receive testing messages.

Parameters:

  • right_method

    message to be sent to tested object. if there is a helper with such a name, the helper are run and result returned.

  • *args

    arguments to be passed to tested object when message sent.

  • &right_proc

    block to be passed to tested object when message sent.

Returns:

  • if some helper matched first argument returns helper’s execution result. returns ‘nil` if test passed. returns a failure if test failed.



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/minispec/proxy.rb', line 101

def __ms__assert right_method, *args, &right_proc
  if helper = @base.class.helpers[right_method]
    return __ms__run_helper(helper, *args, &right_proc)
  end

  result = __ms__send(right_method, *args, &right_proc)

  if @negation           # sometimes
    return unless result # verbosity
  else                   # is
    return if result     # a
  end                    # virtue

  __ms__fail(right_method, right_proc, *args)
end

#__ms__fail(right_method, right_proc, *args) ⇒ Object

builds a MiniSpec failure and pass it to spec’s #fail instance method. using splat cause it should be able to receive ‘nil` and `false` as second argument as well as work without second argument at all.



160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/minispec/proxy.rb', line 160

def __ms__fail right_method, right_proc, *args
  right_object = right_proc ? \
    __ms__proc_definition(right_method.to_s, right_proc) : \
    (args.size > 0 ? args.first : :__ms__right_object)
  failure = {
     left_method: @left_method,
     left_object: __ms__left_object,
    right_method: (@sugar + [right_method])*' ',
    right_object: right_object,
        negation: @negation
  }
  failure[:message] = @failure_message if @failure_message
  @base.send(:fail, failure)
end

#__ms__left_objectObject

computes tested object based on arguments passed at initialize. if a block given it is yielded and returned value used as tested object. otherwise orig ‘@left_object` used. if given block raises an error it will be rescued and returned as tested object.



147
148
149
150
151
152
153
154
155
# File 'lib/minispec/proxy.rb', line 147

def __ms__left_object
  return @left_object_value if @left_object_computed
  @left_object_computed = true
  @left_object_value = begin
    @left_proc ? @base.instance_exec(&@left_proc) : @left_object
  rescue Exception => e
    e
  end
end

#__ms__proc_definition(meth, proc) ⇒ Object

reads what follow after the given method at the line where given proc is defined

Examples:

assure([]).has.any? {|x| x > 1}
# => {|x| x > 1}

Returns:

  • a string if proc is defined in a real file. ‘nil` otherwise (think of irb/pry)



183
184
185
186
187
188
# File 'lib/minispec/proxy.rb', line 183

def __ms__proc_definition meth, proc
  return unless source = __ms__source_line(proc)
  source = source.split(meth)[1..-1].map(&:strip).join(meth)
  def source.inspect; self end
  source
end

#__ms__run_helper(helper, *args, &right_proc) ⇒ Object

executes a helper block earlier defined at class level

Parameters:

  • helper

    helper name

  • *args

    arguments to be passed into helper block



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/minispec/proxy.rb', line 126

def __ms__run_helper helper, *args, &right_proc
  helper_proc, helper_opts = helper
  args.unshift(@left_proc || @left_object)
  args.push(right_proc) if right_proc
  args << {
    left_method: @left_method,
    left_object: @left_object,
      left_proc: @left_proc,
     right_proc: right_proc,
       negation: @negation
  }.freeze if helper_opts[:with_context]
  @base.__ms__inside_helper = true
  @base.instance_exec(*args, &helper_proc)
ensure
  @base.__ms__inside_helper = false
end

#__ms__send(right_method, *args, &right_proc) ⇒ Object

passing received message to tested object



118
119
120
# File 'lib/minispec/proxy.rb', line 118

def __ms__send right_method, *args, &right_proc
  __ms__left_object.__send__(right_method, *args, &right_proc)
end

#__ms__source_line(proc) ⇒ Object

reads the line at which given proc is defined.

Returns:

  • a string if file exists. ‘nil` if file does not exits(think of irb/pry)



194
195
196
197
198
# File 'lib/minispec/proxy.rb', line 194

def __ms__source_line proc
  file, line = proc.source_location
  return unless lines = MiniSpec.source_location_cache(file)
  (line = lines[line - 1]) && line.strip
end

#verbMiniSpec::Proxy

sugar methods that sets negation bit and returns proxy instance.

Examples:

‘is_not_a` will set negation bit and return current proxy instance.

assure(this).is_not_a.instance_of? That

Returns:



87
88
89
# File 'lib/minispec/proxy.rb', line 87

@@negations.each do |verb|
  define_method(verb) { @negation = true; self }
end