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.



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.



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}


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



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.



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


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

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