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