From c631bb6279e577ec108e6ce56884e92a400ddc63 Mon Sep 17 00:00:00 2001 From: John Bintz Date: Fri, 23 Mar 2012 17:46:16 -0400 Subject: [PATCH] pre-gh pages creation --- _site/index.html | 6654 ++++++++++------------------------------------ 1 file changed, 1448 insertions(+), 5206 deletions(-) diff --git a/_site/index.html b/_site/index.html index 2d5570c..6dc7166 100644 --- a/_site/index.html +++ b/_site/index.html @@ -1,5211 +1,1453 @@ - + - - NameError at / +Tea Time: A Beginner's Guide to Jasmine + + + + - - - - -
- - -
-

BACKTRACE

-

(expand)

- -
- -
    - - - - - -
  • - /Users/john/Projects/attentive/views/layout.haml in - evaluate_source -
  • - -
  • - -
      - -
    1. !!! -
    2. - -
    3. %html -
    4. - -
    5. %head -
    6. - -
    7. %title= Attentive.title -
    8. - -
    9. %script{:type => 'text/javascript', :src => 'assets/application.js'} -
    10. - -
    - - -
      -
    1. %style{:type => 'text/css'}= Pygments.css
    2. -
    - - -
      - -
    1. %link{:rel => 'stylesheet', :href => 'assets/application.css', :type => 'text/css'}/ -
    2. - -
    3. = haml :"_header" -
    4. - -
    5. %body.loading -
    6. - -
    7. = yield -
    8. - -
    9. -
    10. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/tilt-1.3.3/lib/tilt/template.rb in - instance_eval -
  • - -
  • - -
      - -
    1. compile_template_method(locals_keys) -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. private -
    8. - -
    9. # Evaluate the template source in the context of the scope object. -
    10. - -
    11. def evaluate_source(scope, locals, &block) -
    12. - -
    13. source, offset = precompiled(locals) -
    14. - -
    - - -
      -
    1. scope.instance_eval(source, eval_file, line - offset)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # JRuby doesn't allow Object#instance_eval to yield to the block it's -
    6. - -
    7. # closed over. This is by design and (ostensibly) something that will -
    8. - -
    9. # change in MRI, though no current MRI version tested (1.8.6 - 1.9.2) -
    10. - -
    11. # exhibits the behavior. More info here: -
    12. - -
    13. # -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/tilt-1.3.3/lib/tilt/template.rb in - evaluate_source -
  • - -
  • - -
      - -
    1. compile_template_method(locals_keys) -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. private -
    8. - -
    9. # Evaluate the template source in the context of the scope object. -
    10. - -
    11. def evaluate_source(scope, locals, &block) -
    12. - -
    13. source, offset = precompiled(locals) -
    14. - -
    - - -
      -
    1. scope.instance_eval(source, eval_file, line - offset)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # JRuby doesn't allow Object#instance_eval to yield to the block it's -
    6. - -
    7. # closed over. This is by design and (ostensibly) something that will -
    8. - -
    9. # change in MRI, though no current MRI version tested (1.8.6 - 1.9.2) -
    10. - -
    11. # exhibits the behavior. More info here: -
    12. - -
    13. # -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/tilt-1.3.3/lib/tilt/template.rb in - cached_evaluate -
  • - -
  • - -
      - -
    1. # Redefine itself to use method compilation the next time: -
    2. - -
    3. def self.cached_evaluate(scope, locals, &block) -
    4. - -
    5. method = compiled_method(locals.keys) -
    6. - -
    7. method.bind(scope).call(locals, &block) -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. # Use instance_eval the first time: -
    14. - -
    - - -
      -
    1. evaluate_source(scope, locals, &block)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # Generates all template source by combining the preamble, template, and -
    6. - -
    7. # postamble and returns a two-tuple of the form: [source, offset], where -
    8. - -
    9. # source is the string containing (Ruby) source code for the template and -
    10. - -
    11. # offset is the integer line offset where line reporting should begin. -
    12. - -
    13. # -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/tilt-1.3.3/lib/tilt/template.rb in - evaluate -
  • - -
  • - -
      - -
    1. compile! -
    2. - -
    3. else -
    4. - -
    5. raise NotImplementedError -
    6. - -
    7. end -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def evaluate(scope, locals, &block) -
    14. - -
    - - -
      -
    1. cached_evaluate(scope, locals, &block)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # Process the template and return the result. The first time this -
    6. - -
    7. # method is called, the template source is evaluated with instance_eval. -
    8. - -
    9. # On the sequential method calls it will compile the template to an -
    10. - -
    11. # unbound method which will lead to better performance. In any case, -
    12. - -
    13. # template executation is guaranteed to be performed in the scope object -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/tilt-1.3.3/lib/tilt/haml.rb in - evaluate -
  • - -
  • - -
      - -
    1. def prepare -
    2. - -
    3. options = @options.merge(:filename => eval_file, :line => line) -
    4. - -
    5. @engine = ::Haml::Engine.new(data, options) -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. def evaluate(scope, locals, &block) -
    12. - -
    13. if @engine.respond_to?(:precompiled_method_return_value, true) -
    14. - -
    - - -
      -
    1. super
    2. -
    - - -
      - -
    1. else -
    2. - -
    3. @engine.render(scope, locals, &block) -
    4. - -
    5. end -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. # Precompiled Haml source. Taken from the precompiled_with_ambles -
    12. - -
    13. # method in Haml::Precompiler: -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/tilt-1.3.3/lib/tilt/template.rb in - render -
  • - -
  • - -
      - -
    1. prepare -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. # Render the template in the given scope with the locals specified. If a -
    8. - -
    9. # block is given, it is typically available within the template via -
    10. - -
    11. # +yield+. -
    12. - -
    13. def render(scope=Object.new, locals={}, &block) -
    14. - -
    - - -
      -
    1. evaluate scope, locals || {}, &block
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # The basename of the template file. -
    6. - -
    7. def basename(suffix='') -
    8. - -
    9. File.basename(file, suffix) if file -
    10. - -
    11. end -
    12. - -
    13. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - render -
  • - -
  • - -
      - -
    1. scope = options.delete(:scope) || self -
    2. - -
    3. -
    4. - -
    5. # compile and render template -
    6. - -
    7. begin -
    8. - -
    9. layout_was = @default_layout -
    10. - -
    11. @default_layout = false -
    12. - -
    13. template = compile_template(engine, data, options, views) -
    14. - -
    - - -
      -
    1. output = template.render(scope, locals, &block)
    2. -
    - - -
      - -
    1. ensure -
    2. - -
    3. @default_layout = layout_was -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. # render layout -
    10. - -
    11. if layout -
    12. - -
    13. options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors, :scope => scope) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/lib/attentive/server.rb in - block in render -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. private -
    4. - -
    5. def render(engine, data, options = {}, locals = {}, &block) -
    6. - -
    7. settings.views.each do |view| -
    8. - -
    9. template = "#{data}.#{engine}" -
    10. - -
    11. -
    12. - -
    13. if File.file?(File.join(view, template)) -
    14. - -
    - - -
      -
    1. return super(engine, data, options.merge(:views => view), locals, &block)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. end -
    6. - -
    7. end -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/lib/attentive/server.rb in - each -
  • - -
  • - -
      - -
    1. haml :index, :ugly => true -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. set :views, [ File.join(Dir.pwd, 'views'), Attentive.root.join('views')] -
    8. - -
    9. -
    10. - -
    11. private -
    12. - -
    13. def render(engine, data, options = {}, locals = {}, &block) -
    14. - -
    - - -
      -
    1. settings.views.each do |view|
    2. -
    - - -
      - -
    1. template = "#{data}.#{engine}" -
    2. - -
    3. -
    4. - -
    5. if File.file?(File.join(view, template)) -
    6. - -
    7. return super(engine, data, options.merge(:views => view), locals, &block) -
    8. - -
    9. end -
    10. - -
    11. end -
    12. - -
    13. end -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/lib/attentive/server.rb in - render -
  • - -
  • - -
      - -
    1. haml :index, :ugly => true -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. set :views, [ File.join(Dir.pwd, 'views'), Attentive.root.join('views')] -
    8. - -
    9. -
    10. - -
    11. private -
    12. - -
    13. def render(engine, data, options = {}, locals = {}, &block) -
    14. - -
    - - -
      -
    1. settings.views.each do |view|
    2. -
    - - -
      - -
    1. template = "#{data}.#{engine}" -
    2. - -
    3. -
    4. - -
    5. if File.file?(File.join(view, template)) -
    6. - -
    7. return super(engine, data, options.merge(:views => view), locals, &block) -
    8. - -
    9. end -
    10. - -
    11. end -
    12. - -
    13. end -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - block in render -
  • - -
  • - -
      - -
    1. ensure -
    2. - -
    3. @default_layout = layout_was -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. # render layout -
    10. - -
    11. if layout -
    12. - -
    13. options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors, :scope => scope) -
    14. - -
    - - -
      -
    1. catch(:layout_missing) { return render(layout_engine, layout, options, locals) { output } }
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. output.extend(ContentTyped).content_type = content_type if content_type -
    6. - -
    7. output -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def compile_template(engine, data, options, views) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - catch -
  • - -
  • - -
      - -
    1. ensure -
    2. - -
    3. @default_layout = layout_was -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. # render layout -
    10. - -
    11. if layout -
    12. - -
    13. options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors, :scope => scope) -
    14. - -
    - - -
      -
    1. catch(:layout_missing) { return render(layout_engine, layout, options, locals) { output } }
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. output.extend(ContentTyped).content_type = content_type if content_type -
    6. - -
    7. output -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def compile_template(engine, data, options, views) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - render -
  • - -
  • - -
      - -
    1. ensure -
    2. - -
    3. @default_layout = layout_was -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. # render layout -
    10. - -
    11. if layout -
    12. - -
    13. options = options.merge(:views => views, :layout => false, :eat_errors => eat_errors, :scope => scope) -
    14. - -
    - - -
      -
    1. catch(:layout_missing) { return render(layout_engine, layout, options, locals) { output } }
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. output.extend(ContentTyped).content_type = content_type if content_type -
    6. - -
    7. output -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def compile_template(engine, data, options, views) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/lib/attentive/server.rb in - block in render -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. private -
    4. - -
    5. def render(engine, data, options = {}, locals = {}, &block) -
    6. - -
    7. settings.views.each do |view| -
    8. - -
    9. template = "#{data}.#{engine}" -
    10. - -
    11. -
    12. - -
    13. if File.file?(File.join(view, template)) -
    14. - -
    - - -
      -
    1. return super(engine, data, options.merge(:views => view), locals, &block)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. end -
    6. - -
    7. end -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/lib/attentive/server.rb in - each -
  • - -
  • - -
      - -
    1. haml :index, :ugly => true -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. set :views, [ File.join(Dir.pwd, 'views'), Attentive.root.join('views')] -
    8. - -
    9. -
    10. - -
    11. private -
    12. - -
    13. def render(engine, data, options = {}, locals = {}, &block) -
    14. - -
    - - -
      -
    1. settings.views.each do |view|
    2. -
    - - -
      - -
    1. template = "#{data}.#{engine}" -
    2. - -
    3. -
    4. - -
    5. if File.file?(File.join(view, template)) -
    6. - -
    7. return super(engine, data, options.merge(:views => view), locals, &block) -
    8. - -
    9. end -
    10. - -
    11. end -
    12. - -
    13. end -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/lib/attentive/server.rb in - render -
  • - -
  • - -
      - -
    1. haml :index, :ugly => true -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. set :views, [ File.join(Dir.pwd, 'views'), Attentive.root.join('views')] -
    8. - -
    9. -
    10. - -
    11. private -
    12. - -
    13. def render(engine, data, options = {}, locals = {}, &block) -
    14. - -
    - - -
      -
    1. settings.views.each do |view|
    2. -
    - - -
      - -
    1. template = "#{data}.#{engine}" -
    2. - -
    3. -
    4. - -
    5. if File.file?(File.join(view, template)) -
    6. - -
    7. return super(engine, data, options.merge(:views => view), locals, &block) -
    8. - -
    9. end -
    10. - -
    11. end -
    12. - -
    13. end -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - haml -
  • - -
  • - -
      - -
    1. def erubis(template, options={}, locals={}) -
    2. - -
    3. warn "Sinatra::Templates#erubis is deprecated and will be removed, use #erb instead.\n" \ -
    4. - -
    5. "If you have Erubis installed, it will be used automatically." -
    6. - -
    7. render :erubis, template, options, locals -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def haml(template, options={}, locals={}) -
    14. - -
    - - -
      -
    1. render :haml, template, options, locals
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. def sass(template, options={}, locals={}) -
    6. - -
    7. options.merge! :layout => false, :default_content_type => :css -
    8. - -
    9. render :sass, template, options, locals -
    10. - -
    11. end -
    12. - -
    13. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/lib/attentive/server.rb in - block in <class:Sinatra> -
  • - -
  • - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. slides.collect(&:to_html).join -
    6. - -
    7. end -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. get %r{/?\d*} do -
    14. - -
    - - -
      -
    1. haml :index, :ugly => true
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. set :views, [ File.join(Dir.pwd, 'views'), Attentive.root.join('views')] -
    6. - -
    7. -
    8. - -
    9. private -
    10. - -
    11. def render(engine, data, options = {}, locals = {}, &block) -
    12. - -
    13. settings.views.each do |view| -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - call -
  • - -
  • - -
      - -
    1. method_name = "#{verb} #{path}" -
    2. - -
    3. unbound_method = generate_method(method_name, &block) -
    4. - -
    5. pattern, keys = compile path -
    6. - -
    7. conditions, @conditions = @conditions, [] -
    8. - -
    9. -
    10. - -
    11. [ pattern, keys, conditions, block.arity != 0 ? -
    12. - -
    13. proc { |a,p| unbound_method.bind(a).call(*p) } : -
    14. - -
    - - -
      -
    1. proc { |a,p| unbound_method.bind(a).call } ]
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. def compile(path) -
    6. - -
    7. keys = [] -
    8. - -
    9. if path.respond_to? :to_str -
    10. - -
    11. pattern = path.to_str.gsub(/[^\?\%\\\/\:\*\w]/) { |c| encoded(c) } -
    12. - -
    13. pattern.gsub!(/((:\w+)|\*)/) do |match| -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - block in compile! -
  • - -
  • - -
      - -
    1. method_name = "#{verb} #{path}" -
    2. - -
    3. unbound_method = generate_method(method_name, &block) -
    4. - -
    5. pattern, keys = compile path -
    6. - -
    7. conditions, @conditions = @conditions, [] -
    8. - -
    9. -
    10. - -
    11. [ pattern, keys, conditions, block.arity != 0 ? -
    12. - -
    13. proc { |a,p| unbound_method.bind(a).call(*p) } : -
    14. - -
    - - -
      -
    1. proc { |a,p| unbound_method.bind(a).call } ]
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. def compile(path) -
    6. - -
    7. keys = [] -
    8. - -
    9. if path.respond_to? :to_str -
    10. - -
    11. pattern = path.to_str.gsub(/[^\?\%\\\/\:\*\w]/) { |c| encoded(c) } -
    12. - -
    13. pattern.gsub!(/((:\w+)|\*)/) do |match| -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - [] -
  • - -
  • - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # Run routes defined on the class and all superclasses. -
    6. - -
    7. def route!(base = settings, pass_block=nil) -
    8. - -
    9. if routes = base.routes[@request.request_method] -
    10. - -
    11. routes.each do |pattern, keys, conditions, block| -
    12. - -
    13. pass_block = process_route(pattern, keys, conditions) do |*args| -
    14. - -
    - - -
      -
    1. route_eval { block[*args] }
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. # Run routes defined in superclass. -
    10. - -
    11. if base.superclass.respond_to?(:routes) -
    12. - -
    13. return route!(base.superclass, pass_block) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - block (3 levels) in route! -
  • - -
  • - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # Run routes defined on the class and all superclasses. -
    6. - -
    7. def route!(base = settings, pass_block=nil) -
    8. - -
    9. if routes = base.routes[@request.request_method] -
    10. - -
    11. routes.each do |pattern, keys, conditions, block| -
    12. - -
    13. pass_block = process_route(pattern, keys, conditions) do |*args| -
    14. - -
    - - -
      -
    1. route_eval { block[*args] }
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. # Run routes defined in superclass. -
    10. - -
    11. if base.superclass.respond_to?(:routes) -
    12. - -
    13. return route!(base.superclass, pass_block) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - route_eval -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. route_eval(&pass_block) if pass_block -
    4. - -
    5. route_missing -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. # Run a route block and throw :halt with the result. -
    12. - -
    13. def route_eval -
    14. - -
    - - -
      -
    1. throw :halt, yield
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # If the current request matches pattern and conditions, fill params -
    6. - -
    7. # with keys and call the given block. -
    8. - -
    9. # Revert params afterwards. -
    10. - -
    11. # -
    12. - -
    13. # Returns pass block. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - block (2 levels) in route! -
  • - -
  • - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # Run routes defined on the class and all superclasses. -
    6. - -
    7. def route!(base = settings, pass_block=nil) -
    8. - -
    9. if routes = base.routes[@request.request_method] -
    10. - -
    11. routes.each do |pattern, keys, conditions, block| -
    12. - -
    13. pass_block = process_route(pattern, keys, conditions) do |*args| -
    14. - -
    - - -
      -
    1. route_eval { block[*args] }
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. # Run routes defined in superclass. -
    10. - -
    11. if base.superclass.respond_to?(:routes) -
    12. - -
    13. return route!(base.superclass, pass_block) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - block in process_route -
  • - -
  • - -
      - -
    1. if values.any? -
    2. - -
    3. original, @params = params, params.merge('splat' => [], 'captures' => values) -
    4. - -
    5. keys.zip(values) { |k,v| (@params[k] ||= '') << v if v } -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. catch(:pass) do -
    12. - -
    13. conditions.each { |c| throw :pass if c.bind(self).call == false } -
    14. - -
    - - -
      -
    1. block ? block[self, values] : yield(self, values)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. ensure -
    4. - -
    5. @params = original if original -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. # No matching route was found or all routes passed. The default -
    12. - -
    13. # implementation is to forward the request downstream when running -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - catch -
  • - -
  • - -
      - -
    1. values += match.captures.to_a.map { |v| force_encoding URI.decode(v) if v } -
    2. - -
    3. -
    4. - -
    5. if values.any? -
    6. - -
    7. original, @params = params, params.merge('splat' => [], 'captures' => values) -
    8. - -
    9. keys.zip(values) { |k,v| (@params[k] ||= '') << v if v } -
    10. - -
    11. end -
    12. - -
    13. -
    14. - -
    - - -
      -
    1. catch(:pass) do
    2. -
    - - -
      - -
    1. conditions.each { |c| throw :pass if c.bind(self).call == false } -
    2. - -
    3. block ? block[self, values] : yield(self, values) -
    4. - -
    5. end -
    6. - -
    7. ensure -
    8. - -
    9. @params = original if original -
    10. - -
    11. end -
    12. - -
    13. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - process_route -
  • - -
  • - -
      - -
    1. values += match.captures.to_a.map { |v| force_encoding URI.decode(v) if v } -
    2. - -
    3. -
    4. - -
    5. if values.any? -
    6. - -
    7. original, @params = params, params.merge('splat' => [], 'captures' => values) -
    8. - -
    9. keys.zip(values) { |k,v| (@params[k] ||= '') << v if v } -
    10. - -
    11. end -
    12. - -
    13. -
    14. - -
    - - -
      -
    1. catch(:pass) do
    2. -
    - - -
      - -
    1. conditions.each { |c| throw :pass if c.bind(self).call == false } -
    2. - -
    3. block ? block[self, values] : yield(self, values) -
    4. - -
    5. end -
    6. - -
    7. ensure -
    8. - -
    9. @params = original if original -
    10. - -
    11. end -
    12. - -
    13. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - block in route! -
  • - -
  • - -
      - -
    1. base.filters[type].each { |args| process_route(*args) } -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. # Run routes defined on the class and all superclasses. -
    8. - -
    9. def route!(base = settings, pass_block=nil) -
    10. - -
    11. if routes = base.routes[@request.request_method] -
    12. - -
    13. routes.each do |pattern, keys, conditions, block| -
    14. - -
    - - -
      -
    1. pass_block = process_route(pattern, keys, conditions) do |*args|
    2. -
    - - -
      - -
    1. route_eval { block[*args] } -
    2. - -
    3. end -
    4. - -
    5. end -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. # Run routes defined in superclass. -
    12. - -
    13. if base.superclass.respond_to?(:routes) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - each -
  • - -
  • - -
      - -
    1. filter! type, base.superclass if base.superclass.respond_to?(:filters) -
    2. - -
    3. base.filters[type].each { |args| process_route(*args) } -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. # Run routes defined on the class and all superclasses. -
    10. - -
    11. def route!(base = settings, pass_block=nil) -
    12. - -
    13. if routes = base.routes[@request.request_method] -
    14. - -
    - - -
      -
    1. routes.each do |pattern, keys, conditions, block|
    2. -
    - - -
      - -
    1. pass_block = process_route(pattern, keys, conditions) do |*args| -
    2. - -
    3. route_eval { block[*args] } -
    4. - -
    5. end -
    6. - -
    7. end -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. # Run routes defined in superclass. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - route! -
  • - -
  • - -
      - -
    1. filter! type, base.superclass if base.superclass.respond_to?(:filters) -
    2. - -
    3. base.filters[type].each { |args| process_route(*args) } -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. # Run routes defined on the class and all superclasses. -
    10. - -
    11. def route!(base = settings, pass_block=nil) -
    12. - -
    13. if routes = base.routes[@request.request_method] -
    14. - -
    - - -
      -
    1. routes.each do |pattern, keys, conditions, block|
    2. -
    - - -
      - -
    1. pass_block = process_route(pattern, keys, conditions) do |*args| -
    2. - -
    3. route_eval { block[*args] } -
    4. - -
    5. end -
    6. - -
    7. end -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. # Run routes defined in superclass. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - dispatch! -
  • - -
  • - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. # Dispatch a request with error handling. -
    8. - -
    9. def dispatch! -
    10. - -
    11. static! if settings.static? && (request.get? || request.head?) -
    12. - -
    13. filter! :before -
    14. - -
    - - -
      -
    1. route!
    2. -
    - - -
      - -
    1. rescue ::Exception => boom -
    2. - -
    3. handle_exception!(boom) -
    4. - -
    5. ensure -
    6. - -
    7. filter! :after unless env['sinatra.static_file'] -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. # Error handling during requests. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - block in call! -
  • - -
  • - -
      - -
    1. @request = Request.new(env) -
    2. - -
    3. @response = Response.new -
    4. - -
    5. @params = indifferent_params(@request.params) -
    6. - -
    7. template_cache.clear if settings.reload_templates -
    8. - -
    9. force_encoding(@params) -
    10. - -
    11. -
    12. - -
    13. @response['Content-Type'] = nil -
    14. - -
    - - -
      -
    1. invoke { dispatch! }
    2. -
    - - -
      - -
    1. invoke { error_block!(response.status) } -
    2. - -
    3. -
    4. - -
    5. unless @response['Content-Type'] -
    6. - -
    7. if Array === body and body[0].respond_to? :content_type -
    8. - -
    9. content_type body[0].content_type -
    10. - -
    11. else -
    12. - -
    13. content_type :html -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - block in invoke -
  • - -
  • - -
      - -
    1. # Creates a Hash with indifferent access. -
    2. - -
    3. def indifferent_hash -
    4. - -
    5. Hash.new {|hash,key| hash[key.to_s] if Symbol === key } -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. # Run the block with 'throw :halt' support and apply result to the response. -
    12. - -
    13. def invoke -
    14. - -
    - - -
      -
    1. res = catch(:halt) { yield }
    2. -
    - - -
      - -
    1. res = [res] if Fixnum === res or String === res -
    2. - -
    3. if Array === res and Fixnum === res.first -
    4. - -
    5. status(res.shift) -
    6. - -
    7. body(res.pop) -
    8. - -
    9. headers(*res) -
    10. - -
    11. elsif res.respond_to? :each -
    12. - -
    13. body res -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - catch -
  • - -
  • - -
      - -
    1. # Creates a Hash with indifferent access. -
    2. - -
    3. def indifferent_hash -
    4. - -
    5. Hash.new {|hash,key| hash[key.to_s] if Symbol === key } -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. # Run the block with 'throw :halt' support and apply result to the response. -
    12. - -
    13. def invoke -
    14. - -
    - - -
      -
    1. res = catch(:halt) { yield }
    2. -
    - - -
      - -
    1. res = [res] if Fixnum === res or String === res -
    2. - -
    3. if Array === res and Fixnum === res.first -
    4. - -
    5. status(res.shift) -
    6. - -
    7. body(res.pop) -
    8. - -
    9. headers(*res) -
    10. - -
    11. elsif res.respond_to? :each -
    12. - -
    13. body res -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - invoke -
  • - -
  • - -
      - -
    1. # Creates a Hash with indifferent access. -
    2. - -
    3. def indifferent_hash -
    4. - -
    5. Hash.new {|hash,key| hash[key.to_s] if Symbol === key } -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. # Run the block with 'throw :halt' support and apply result to the response. -
    12. - -
    13. def invoke -
    14. - -
    - - -
      -
    1. res = catch(:halt) { yield }
    2. -
    - - -
      - -
    1. res = [res] if Fixnum === res or String === res -
    2. - -
    3. if Array === res and Fixnum === res.first -
    4. - -
    5. status(res.shift) -
    6. - -
    7. body(res.pop) -
    8. - -
    9. headers(*res) -
    10. - -
    11. elsif res.respond_to? :each -
    12. - -
    13. body res -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - call! -
  • - -
  • - -
      - -
    1. @request = Request.new(env) -
    2. - -
    3. @response = Response.new -
    4. - -
    5. @params = indifferent_params(@request.params) -
    6. - -
    7. template_cache.clear if settings.reload_templates -
    8. - -
    9. force_encoding(@params) -
    10. - -
    11. -
    12. - -
    13. @response['Content-Type'] = nil -
    14. - -
    - - -
      -
    1. invoke { dispatch! }
    2. -
    - - -
      - -
    1. invoke { error_block!(response.status) } -
    2. - -
    3. -
    4. - -
    5. unless @response['Content-Type'] -
    6. - -
    7. if Array === body and body[0].respond_to? :content_type -
    8. - -
    9. content_type body[0].content_type -
    10. - -
    11. else -
    12. - -
    13. content_type :html -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - call -
  • - -
  • - -
      - -
    1. @app = app -
    2. - -
    3. @template_cache = Tilt::Cache.new -
    4. - -
    5. yield self if block_given? -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. # Rack call interface. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. dup.call!(env)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. attr_accessor :env, :request, :response, :params -
    6. - -
    7. -
    8. - -
    9. def call!(env) # :nodoc: -
    10. - -
    11. @env = env -
    12. - -
    13. @request = Request.new(env) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-protection-1.2.0/lib/rack/protection/xss_header.rb in - call -
  • - -
  • - -
      - -
    1. default_options :xss_mode => :block -
    2. - -
    3. -
    4. - -
    5. def header -
    6. - -
    7. { 'X-XSS-Protection' => "1; mode=#{options[:xss_mode]}" } -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. status, headers, body = @app.call(env)
    2. -
    - - -
      - -
    1. [status, header.merge(headers), body] -
    2. - -
    3. end -
    4. - -
    5. end -
    6. - -
    7. end -
    8. - -
    9. end -
    10. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-protection-1.2.0/lib/rack/protection/path_traversal.rb in - call -
  • - -
  • - -
      - -
    1. # -
    2. - -
    3. # Unescapes '/' and '.', expands +path_info+. -
    4. - -
    5. # Thus <tt>GET /foo/%2e%2e%2fbar</tt> becomes <tt>GET /bar</tt>. -
    6. - -
    7. class PathTraversal < Base -
    8. - -
    9. def call(env) -
    10. - -
    11. path_was = env["PATH_INFO"] -
    12. - -
    13. env["PATH_INFO"] = cleanup path_was if path_was -
    14. - -
    - - -
      -
    1. app.call env
    2. -
    - - -
      - -
    1. ensure -
    2. - -
    3. env["PATH_INFO"] = path_was -
    4. - -
    5. end -
    6. - -
    7. -
    8. - -
    9. def cleanup(path) -
    10. - -
    11. parts = [] -
    12. - -
    13. unescaped = path.gsub('%2e', '.').gsub('%2f', '/') -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-protection-1.2.0/lib/rack/protection/json_csrf.rb in - call -
  • - -
  • - -
      - -
    1. # JSON GET APIs are vulnerable to being embedded as JavaScript while the -
    2. - -
    3. # Array prototype has been patched to track data. Checks the referrer -
    4. - -
    5. # even on GET requests if the content type is JSON. -
    6. - -
    7. class JsonCsrf < Base -
    8. - -
    9. default_reaction :deny -
    10. - -
    11. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. status, headers, body = app.call(env)
    2. -
    - - -
      - -
    1. if headers['Content-Type'].to_s.split(';', 2).first =~ /^\s*application\/json\s*$/ -
    2. - -
    3. if referrer(env) != Request.new(env).host -
    4. - -
    5. result = react(env) -
    6. - -
    7. warn env, "attack prevented by #{self.class}" -
    8. - -
    9. end -
    10. - -
    11. end -
    12. - -
    13. result or [status, headers, body] -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-protection-1.2.0/lib/rack/protection/base.rb in - call -
  • - -
  • - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. def call(env) -
    6. - -
    7. unless accepts? env -
    8. - -
    9. warn env, "attack prevented by #{self.class}" -
    10. - -
    11. result = react env -
    12. - -
    13. end -
    14. - -
    - - -
      -
    1. result or app.call(env)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. def react(env) -
    6. - -
    7. result = send(options[:reaction], env) -
    8. - -
    9. result if Array === result and result.size == 3 -
    10. - -
    11. end -
    12. - -
    13. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-protection-1.2.0/lib/rack/protection/xss_header.rb in - call -
  • - -
  • - -
      - -
    1. default_options :xss_mode => :block -
    2. - -
    3. -
    4. - -
    5. def header -
    6. - -
    7. { 'X-XSS-Protection' => "1; mode=#{options[:xss_mode]}" } -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. status, headers, body = @app.call(env)
    2. -
    - - -
      - -
    1. [status, header.merge(headers), body] -
    2. - -
    3. end -
    4. - -
    5. end -
    6. - -
    7. end -
    8. - -
    9. end -
    10. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-1.4.1/lib/rack/logger.rb in - call -
  • - -
  • - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. def call(env) -
    6. - -
    7. logger = ::Logger.new(env['rack.errors']) -
    8. - -
    9. logger.level = @level -
    10. - -
    11. -
    12. - -
    13. env['rack.logger'] = logger -
    14. - -
    - - -
      -
    1. @app.call(env)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. end -
    6. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-1.4.1/lib/rack/head.rb in - call -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. class Head -
    4. - -
    5. def initialize(app) -
    6. - -
    7. @app = app -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. status, headers, body = @app.call(env)
    2. -
    - - -
      - -
    1. -
    2. - -
    3. if env["REQUEST_METHOD"] == "HEAD" -
    4. - -
    5. [status, headers, []] -
    6. - -
    7. else -
    8. - -
    9. [status, headers, body] -
    10. - -
    11. end -
    12. - -
    13. end -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/showexceptions.rb in - call -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. def initialize(app) -
    4. - -
    5. @app = app -
    6. - -
    7. @template = ERB.new(TEMPLATE) -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. @app.call(env)
    2. -
    - - -
      - -
    1. rescue Exception => e -
    2. - -
    3. errors, env["rack.errors"] = env["rack.errors"], @@eats_errors -
    4. - -
    5. -
    6. - -
    7. if respond_to?(:prefers_plain_text?) and prefers_plain_text?(env) -
    8. - -
    9. content_type = "text/plain" -
    10. - -
    11. body = [dump_exception(e)] -
    12. - -
    13. else -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - block in call -
  • - -
  • - -
      - -
    1. setup_default_middleware builder -
    2. - -
    3. setup_middleware builder -
    4. - -
    5. builder.run new!(*args, &bk) -
    6. - -
    7. builder -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. synchronize { prototype.call(env) }
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. private -
    6. - -
    7. def setup_default_middleware(builder) -
    8. - -
    9. builder.use ShowExceptions if show_exceptions? -
    10. - -
    11. builder.use Rack::MethodOverride if method_override? -
    12. - -
    13. builder.use Rack::Head -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - synchronize -
  • - -
  • - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. @@mutex = Mutex.new -
    6. - -
    7. def synchronize(&block) -
    8. - -
    9. if lock? -
    10. - -
    11. @@mutex.synchronize(&block) -
    12. - -
    13. else -
    14. - -
    - - -
      -
    1. yield
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. public -
    8. - -
    9. CALLERS_TO_IGNORE = [ # :nodoc: -
    10. - -
    11. /\/sinatra(\/(base|main|showexceptions))?\.rb$/, # all sinatra code -
    12. - -
    13. /lib\/tilt.*\.rb$/, # all tilt code -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/sinatra-1.3.2/lib/sinatra/base.rb in - call -
  • - -
  • - -
      - -
    1. setup_default_middleware builder -
    2. - -
    3. setup_middleware builder -
    4. - -
    5. builder.run new!(*args, &bk) -
    6. - -
    7. builder -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. synchronize { prototype.call(env) }
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. private -
    6. - -
    7. def setup_default_middleware(builder) -
    8. - -
    9. builder.use ShowExceptions if show_exceptions? -
    10. - -
    11. builder.use Rack::MethodOverride if method_override? -
    12. - -
    13. builder.use Rack::Head -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-1.4.1/lib/rack/builder.rb in - call -
  • - -
  • - -
      - -
    1. def to_app -
    2. - -
    3. app = @map ? generate_map(@run, @map) : @run -
    4. - -
    5. fail "missing run or map statement" unless app -
    6. - -
    7. @use.reverse.inject(app) { |a,e| e[a] } -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. to_app.call(env)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. private -
    6. - -
    7. -
    8. - -
    9. def generate_map(default_app, mapping) -
    10. - -
    11. mapped = default_app ? {'/' => default_app} : {} -
    12. - -
    13. mapping.each { |r,b| mapped[r] = self.class.new(default_app, &b) } -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-1.4.1/lib/rack/urlmap.rb in - block in call -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. rest = m[1] -
    4. - -
    5. next unless !rest || rest.empty? || rest[0] == ?/ -
    6. - -
    7. -
    8. - -
    9. env['SCRIPT_NAME'] = (script_name + location) -
    10. - -
    11. env['PATH_INFO'] = rest -
    12. - -
    13. -
    14. - -
    - - -
      -
    1. return app.call(env)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. [404, {"Content-Type" => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]] -
    6. - -
    7. -
    8. - -
    9. ensure -
    10. - -
    11. env['PATH_INFO'] = path -
    12. - -
    13. env['SCRIPT_NAME'] = script_name -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-1.4.1/lib/rack/urlmap.rb in - each -
  • - -
  • - -
      - -
    1. def call(env) -
    2. - -
    3. path = env["PATH_INFO"] -
    4. - -
    5. script_name = env['SCRIPT_NAME'] -
    6. - -
    7. hHost = env['HTTP_HOST'] -
    8. - -
    9. sName = env['SERVER_NAME'] -
    10. - -
    11. sPort = env['SERVER_PORT'] -
    12. - -
    13. -
    14. - -
    - - -
      -
    1. @mapping.each do |host, location, match, app|
    2. -
    - - -
      - -
    1. unless hHost == host \ -
    2. - -
    3. || sName == host \ -
    4. - -
    5. || (!host && (hHost == sName || hHost == sName+':'+sPort)) -
    6. - -
    7. next -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. next unless m = match.match(path.to_s) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-1.4.1/lib/rack/urlmap.rb in - call -
  • - -
  • - -
      - -
    1. def call(env) -
    2. - -
    3. path = env["PATH_INFO"] -
    4. - -
    5. script_name = env['SCRIPT_NAME'] -
    6. - -
    7. hHost = env['HTTP_HOST'] -
    8. - -
    9. sName = env['SERVER_NAME'] -
    10. - -
    11. sPort = env['SERVER_PORT'] -
    12. - -
    13. -
    14. - -
    - - -
      -
    1. @mapping.each do |host, location, match, app|
    2. -
    - - -
      - -
    1. unless hHost == host \ -
    2. - -
    3. || sName == host \ -
    4. - -
    5. || (!host && (hHost == sName || hHost == sName+':'+sPort)) -
    6. - -
    7. next -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. next unless m = match.match(path.to_s) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/rack-1.4.1/lib/rack/builder.rb in - call -
  • - -
  • - -
      - -
    1. def to_app -
    2. - -
    3. app = @map ? generate_map(@run, @map) : @run -
    4. - -
    5. fail "missing run or map statement" unless app -
    6. - -
    7. @use.reverse.inject(app) { |a,e| e[a] } -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. def call(env) -
    14. - -
    - - -
      -
    1. to_app.call(env)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. private -
    6. - -
    7. -
    8. - -
    9. def generate_map(default_app, mapping) -
    10. - -
    11. mapped = default_app ? {'/' => default_app} : {} -
    12. - -
    13. mapping.each { |r,b| mapped[r] = self.class.new(default_app, &b) } -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/lib/attentive/server.rb in - call -
  • - -
  • - -
      - -
    1. use(*opts) -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. run Attentive::Sinatra -
    8. - -
    9. end -
    10. - -
    11. end -
    12. - -
    13. -
    14. - -
    - - -
      -
    1. @app.call(env)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. class Highlight -
    8. - -
    9. attr_reader :code, :lang -
    10. - -
    11. -
    12. - -
    13. def self.run(*args) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/bin/attentive in - block in static -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. FileUtils.rm_rf target_dir -
    4. - -
    5. FileUtils.mkdir_p target_dir -
    6. - -
    7. -
    8. - -
    9. Attentive.middleware.replace([]) -
    10. - -
    11. -
    12. - -
    13. urls.each do |url| -
    14. - -
    - - -
      -
    1. response = Attentive::Server.call(Rack::MockRequest.env_for(url))
    2. -
    - - -
      - -
    1. -
    2. - -
    3. target = "#{target_dir}#{url}" -
    4. - -
    5. target += "index.html" if target[-1..-1] == '/' -
    6. - -
    7. -
    8. - -
    9. puts "Writing #{target}..." -
    10. - -
    11. -
    12. - -
    13. FileUtils.mkdir_p(File.dirname(target)) -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/bin/attentive in - each -
  • - -
  • - -
      - -
    1. target_dir = "_site" -
    2. - -
    3. -
    4. - -
    5. FileUtils.rm_rf target_dir -
    6. - -
    7. FileUtils.mkdir_p target_dir -
    8. - -
    9. -
    10. - -
    11. Attentive.middleware.replace([]) -
    12. - -
    13. -
    14. - -
    - - -
      -
    1. urls.each do |url|
    2. -
    - - -
      - -
    1. response = Attentive::Server.call(Rack::MockRequest.env_for(url)) -
    2. - -
    3. -
    4. - -
    5. target = "#{target_dir}#{url}" -
    6. - -
    7. target += "index.html" if target[-1..-1] == '/' -
    8. - -
    9. -
    10. - -
    11. puts "Writing #{target}..." -
    12. - -
    13. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/bin/attentive in - static -
  • - -
  • - -
      - -
    1. target_dir = "_site" -
    2. - -
    3. -
    4. - -
    5. FileUtils.rm_rf target_dir -
    6. - -
    7. FileUtils.mkdir_p target_dir -
    8. - -
    9. -
    10. - -
    11. Attentive.middleware.replace([]) -
    12. - -
    13. -
    14. - -
    - - -
      -
    1. urls.each do |url|
    2. -
    - - -
      - -
    1. response = Attentive::Server.call(Rack::MockRequest.env_for(url)) -
    2. - -
    3. -
    4. - -
    5. target = "#{target_dir}#{url}" -
    6. - -
    7. target += "index.html" if target[-1..-1] == '/' -
    8. - -
    9. -
    10. - -
    11. puts "Writing #{target}..." -
    12. - -
    13. -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/bin/attentive in - gh_pages -
  • - -
  • - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. FileUtils.rm_rf '.sass-cache' if File.directory?('.sass-cache') -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. desc "gh-pages", "Commit the static site to the associated GitHub pages account" -
    12. - -
    13. def gh_pages -
    14. - -
    - - -
      -
    1. static
    2. -
    - - -
      - -
    1. -
    2. - -
    3. target = "/tmp/attentive-#{Time.now.to_i}" -
    4. - -
    5. -
    6. - -
    7. system %{cp -Rpv _site #{target}} -
    8. - -
    9. -
    10. - -
    11. system %{git checkout gh-pages} -
    12. - -
    13. if $?.exitstatus == 1 -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/thor-0.14.6/lib/thor/task.rb in - run -
  • - -
  • - -
      - -
    1. false -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. # By default, a task invokes a method in the thor class. You can change this -
    8. - -
    9. # implementation to create custom tasks. -
    10. - -
    11. def run(instance, args=[]) -
    12. - -
    13. public_method?(instance) ? -
    14. - -
    - - -
      -
    1. instance.send(name, *args) : instance.class.handle_no_task_error(name)
    2. -
    - - -
      - -
    1. rescue ArgumentError => e -
    2. - -
    3. handle_argument_error?(instance, e, caller) ? -
    4. - -
    5. instance.class.handle_argument_error(self, e) : (raise e) -
    6. - -
    7. rescue NoMethodError => e -
    8. - -
    9. handle_no_method_error?(instance, e, caller) ? -
    10. - -
    11. instance.class.handle_no_task_error(name) : (raise e) -
    12. - -
    13. end -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/thor-0.14.6/lib/thor/invocation.rb in - invoke_task -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. # Invoke the given task if the given args. -
    4. - -
    5. def invoke_task(task, *args) #:nodoc: -
    6. - -
    7. current = @_invocations[self.class] -
    8. - -
    9. -
    10. - -
    11. unless current.include?(task.name) -
    12. - -
    13. current << task.name -
    14. - -
    - - -
      -
    1. task.run(self, *args)
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. # Invoke all tasks for the current instance. -
    8. - -
    9. def invoke_all #:nodoc: -
    10. - -
    11. self.class.all_tasks.map { |_, task| invoke_task(task) } -
    12. - -
    13. end -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/thor-0.14.6/lib/thor.rb in - dispatch -
  • - -
  • - -
      - -
    1. task = Thor::DynamicTask.new(meth) -
    2. - -
    3. end -
    4. - -
    5. -
    6. - -
    7. opts = given_opts || opts || [] -
    8. - -
    9. config.merge!(:current_task => task, :task_options => task.options) -
    10. - -
    11. -
    12. - -
    13. trailing = args[Range.new(arguments.size, -1)] -
    14. - -
    - - -
      -
    1. new(args, opts, config).invoke_task(task, trailing || [])
    2. -
    - - -
      - -
    1. end -
    2. - -
    3. -
    4. - -
    5. # The banner for this class. You can customize it if you are invoking the -
    6. - -
    7. # thor class by another ways which is not the Thor::Runner. It receives -
    8. - -
    9. # the task that is going to be invoked and a boolean which indicates if -
    10. - -
    11. # the namespace should be displayed as arguments. -
    12. - -
    13. # -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/thor-0.14.6/lib/thor/base.rb in - start -
  • - -
  • - -
      - -
    1. # -
    2. - -
    3. # script = MyScript.new(args, options, config) -
    4. - -
    5. # script.invoke(:task, first_arg, second_arg, third_arg) -
    6. - -
    7. # -
    8. - -
    9. def start(given_args=ARGV, config={}) -
    10. - -
    11. self.debugging = given_args.delete("--debug") -
    12. - -
    13. config[:shell] ||= Thor::Base.shell.new -
    14. - -
    - - -
      -
    1. dispatch(nil, given_args.dup, nil, config)
    2. -
    - - -
      - -
    1. rescue Thor::Error => e -
    2. - -
    3. debugging ? (raise e) : config[:shell].error(e.message) -
    4. - -
    5. exit(1) if exit_on_failure? -
    6. - -
    7. end -
    8. - -
    9. -
    10. - -
    11. # Allows to use private methods from parent in child classes as tasks. -
    12. - -
    13. # -
    14. - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/Projects/attentive/bin/attentive in - <top (required)> -
  • - -
  • - -
      - -
    1. system %{git add .} -
    2. - -
    3. system %{git add *} -
    4. - -
    5. system %{git commit -a -m "Update published site"} -
    6. - -
    7. system %{git checkout master} -
    8. - -
    9. end -
    10. - -
    11. end -
    12. - -
    13. -
    14. - -
    - - -
      -
    1. Attentive::CLI.start
    2. -
    - - -
      - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/bin/attentive in - load -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then -
    4. - -
    5. version = $1 -
    6. - -
    7. ARGV.shift -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. gem 'attentive', version -
    14. - -
    - - -
      -
    1. load Gem.bin_path('attentive', 'attentive', version)
    2. -
    - - -
      - -
    - -
    -
  • - - - - - - - -
  • - /Users/john/.rvm/gems/ruby-1.9.3-p125/bin/attentive in - <main> -
  • - -
  • - -
      - -
    1. -
    2. - -
    3. if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then -
    4. - -
    5. version = $1 -
    6. - -
    7. ARGV.shift -
    8. - -
    9. end -
    10. - -
    11. -
    12. - -
    13. gem 'attentive', version -
    14. - -
    - - -
      -
    1. load Gem.bin_path('attentive', 'attentive', version)
    2. -
    - - -
      - -
    - -
    -
  • - - - - - - -
-
- -
-

GET

- -

No GET data.

- -
-
- -
-

POST

- -

No POST data.

- -
-
- -
- - -

No cookie data.

- -
-
- -
-

Rack ENV

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VariableValue
CONTENT_LENGTH
0
HTTPS
off
PATH_INFO
/
QUERY_STRING
REQUEST_METHOD
GET
SCRIPT_NAME
SERVER_NAME
example.org
SERVER_PORT
80
rack.errors
#<Object:0x000001009d7f78>
rack.input
#<StringIO:0x00000100bb2028>
rack.logger
#<Logger:0x0000010116e7f0 @progname=nil, @level=1, @default_formatter=#<Logger::Formatter:0x0000010116e7c8 @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0x0000010116e688 @shift_size=nil, @shift_age=nil, @filename=nil, @dev=#<StringIO:0x00000100bb20f0>, @mutex=#<Logger::LogDevice::LogDeviceMutex:0x0000010116e520 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0x0000010116e368>>>>
rack.multiprocess
true
rack.multithread
true
rack.request.cookie_hash
{}
rack.request.query_hash
{}
rack.request.query_string
rack.run_once
false
rack.url_scheme
http
rack.version
[1, 1]
sinatra.error
#<NameError: uninitialized constant Attentive::Sinatra::Pygments>
-
-
- -

You're seeing this error because you have -enabled the show_exceptions setting.

-
- + +
+
+
+ +
+

Tea Time

+

A Beginner's Guide to JavaScript Testing using Jasmine

+

By John Bintz

+
+
+ + + + +
+

Automated testing is important

+ +
+

Why is it important?

+ +
+

+ +
+

Fortunately, we're beyond that nowadays

+ +
+
require 'spec_helper'
+
+describe MyCoolWebsite do
+  let(:website) { described_class.new }
+
+  describe '#cool_method' do
+    subject { website.cool_method }
+
+    let(:oh_yeah) { [ double_cool ] }
+    let(:double_cool) { 'double cool' }
+
+    before do
+      website.stubs(:whoa_cool).returns(oh_yeah)
+    end
+
+    it { should == double_cool }
+  end
+end
+
+ + + + +
+

But there's more to web apps than Ruby nowadays...

+ +
+
<img src="normal.gif"
+   onmouseover="this.src='hover.gif'"
+   onmouseout="this.src='normal.gif'" />
+
+ + + + +
+
<script type="text/javascript">
+function showMyCoolTitle(title, length) {
+  if (length == null) { length = 0; }
+
+  if (length <= title.length) {
+    document.title = title.substr(0, length);
+    length++;
+
+    setTimeout(function() { showMyCoolTitle(title, length); }, 75);
+  }
+}
+
+window.onload = function() {
+  showMyCoolTitle("My cool website! Whoaaaaa!");
+}
+</script>
+
+ + + + +
+

jQuery

+ +
+

Backbone

+ +
+

Sprockets and RequireJS

+ +
+

Automated testing is important

+ +
+
require 'spec_helper'
+
+describe MyCoolWebsite do
+  let(:website) { described_class.new }
+
+  describe '#cool_method' do
+    subject { website.cool_method }
+
+    let(:oh_yeah) { [ double_cool ] }
+    let(:double_cool) { 'double cool' }
+
+    before do
+      website.stubs(:whoa_cool).returns(oh_yeah)
+    end
+
+    it { should == double_cool }
+  end
+end
+
+ + + + +
+
describe 'MyCoolWebsiteView', ->
+  website = null
+
+  beforeEach ->
+    website = new MyCoolWebsiteView()
+
+  describe '#coolMethod', ->
+    doubleCool = 'double cool'
+    ohYeah = [ doubleCool ]
+
+    beforeEach ->
+      website.whoaCool = -> ohYeah
+
+    it 'should be double cool', ->
+      expect(website.coolMethod()).toEqual(doubleCool)
+
+ + + + +
+

Jasmine

+ +
+

BDD unit testing framework for JavaScript

+ +
+

Platform independent

+ +
+

Easily extended

+ +
+

Very easy to learn!

+ +
+

Follow along!

+ +
+

No need to install anything right now

+ +
+

Specs on the left

+ +
+

Code under test on the right

+ +
+

Write code in CoffeeScript

+ +
+

Ready?

+ +
+

Let's go!

+ +
+

describe

+ +
+

Describes a thing or a behavior of a thing

+ +
+

Let's describe...

+ +
+

+ +
+
describe 'Cat', ->
+  # cat behavior descriptions go here
+
+ + + + +
+

Something that cats do...

+ +
+

+ +
+
describe 'Cat', ->
+  describe '#meow', ->
+    # description of the meow behavior goes here
+
+ + + + +
+

John behavior #1

+ +

Use Ruby-style indicators for instance- and class-level methods, even in Jasmine

+ +
describe 'John', ->
+  describe 'spec definitions', ->
+    it 'should look like you did it in RSpec', ->
+
+ + + + +
+

Describe how we expect a cat to meow

+ +
+

it

+ +
+
describe 'Cat', ->
+  describe '#meow', ->
+    it 'should meow correctly', ->
+      # expectation of a cat meowing
+
+ + + + +
+

We have the description...

+ +
+

Now let's add the expectations!

+ +
+

expect

+ +
+

What should we get as an output?

+ +
+
describe 'Cat', ->
+  describe '#meow', ->
+    it 'should meow correctly', ->
+      expect(cat.meow()).toEqual('meow')
+
+ + + + +
+

Wait, we need a cat.

+ +
+
describe 'Cat', ->
+  describe '#meow', ->
+    it 'should meow correctly', ->
+      cat = new Cat()
+
+      expect(cat.meow()).toEqual('meow')
+
+ + + + +
+
# code-under-test
+
+class this.Cat
+  meow: ->
+
+ + + + +
+
// safety wrapper to prevent global pollution
+(function() {
+  // ...but we want to pollute the Cat class
+  this.Cat = (function() {
+    function Cat() {}
+    Cat.prototype.meow = function() {};
+    return Cat;
+  })();
+})(this) // this is window in a browser
+
+ + + + +
+

Run it!

+ +
+
1 spec, 1 failure
+
+Expected undefined to equal 'meow'.
+
+ + + + +
+

Make it meow!

+ +
+
class this.Cat
+  meow: -> "meow"
+
+ + + + +
+
1 spec, 0 failures
+
+ + + + +
+

Here's what you should have meow...

+ +
+
# spec
+
+describe 'Cat', ->
+  describe '#meow', ->
+    it 'should meow correctly', ->
+      expect(cat.meow()).toEqual('meow')
+
+ + + + +
+
# code-under-test
+
+class this.Cat
+  meow: -> "meow"
+
+ + +
+

What if the cat meows differently based on certain states?

+ +
+

+ +
+

+ +
+

Nested describe

+ +
+
describe 'Cat', ->
+  describe '#meow', ->
+    describe 'hungry', ->
+      # Cat#meow expectation for when
+      # the cat is hungry
+
+    describe 'going to the vet', ->
+      # Cat#meow expectation for when
+      # the cat knows it's vet time
+
+ + + + +
+
describe 'Cat', ->
+  describe '#meow', ->
+    describe 'hungry', ->
+      it 'should be a mournful meow', ->
+        cat = new Cat()
+        cat.state = -> Cat.HUNGRY
+          # ...just like cat.stubs(:state)
+
+        expect(cat.meow()).toEqual("meeeyaow")
+
+    describe 'going to the vet', ->
+      it 'should be an evil meow', ->
+        cat = new Cat()
+        cat.state = -> Cat.VET_PSYCHIC
+          # ...just like the one above
+
+        expect(cat.meow()).toEqual("raowwww")
+
+ + + + +
+

+ +
+
cat = new Cat()
+
+ + + + +
+
before do
+  @cat = Cat.new
+end
+
+it 'should be a mournful meow' do
+  @cat.stubs(:state).returns(Cat::HUNGRY)
+
+  @cat.meow.should == "meeyaow"
+end
+
+ + + + +
+
before -> it -> after
+
+ + + + +
+
before do
+  @instance_variable = "yes"
+end
+
+it "is in same context as before block" do
+  @instance_variable.should == "yes"
+end
+
+ + + + +
+
beforeEach -> it -> afterEach
+
+ + + + +
+
beforeEach ->
+  @instanceVariable = "yes"
+
+it "should be in the same context", ->
+  expect(@instanceVariable).toEqual("yes")
+
+ + + + +
+
describe 'Cat', ->
+  describe '#meow', ->
+    beforeEach ->
+      @cat = new Cat()
+
+    describe 'hungry', ->
+      it 'should be a mournful meow', ->
+        @cat.state = -> Cat.HUNGRY
+
+        expect(@cat.meow()).toEqual("meeeyaow")
+
+    describe 'going to the vet', ->
+      it 'should be an evil meow', ->
+        @cat.state = -> Cat.VET_PSYCHIC
+
+        expect(@cat.meow()).toEqual("raowwww")
+
+ + + + +
+

A little semantics game...

+ +
+
describe 'Cat', ->
+  describe '#meow', ->
+    describe 'hungry', ->
+      # cat codes
+
+    describe 'going to the vet', ->
+      # moar cat codes
+
+ + + + +
+

This works, but it can be clearer

+ +
+
describe Cat do
+  describe '#meow' do
+    describe 'hungry' do
+      # cat codes
+    end
+
+    describe 'going to the vet' do
+      # moar cat codes
+    end
+  end
+end
+
+ + + + +
+

context

+ +
+

Description of different states for a test

+ +
+
alias :context :describe
+
+ + + + +
+
describe Cat do
+  let(:cat) { described_class.new }
+
+  # save describe for things or behaviors...
+  describe '#meow' do
+    subject { cat.meow }
+
+    # use context to describe states
+    context 'hungry' do
+      # cat codes
+    end
+
+    context 'going to the vet' do
+      # moar cat codes
+    end
+  end
+end
+
+ + + + +
+

Jasmine doesn't have context

+ +
+

However...

+ +
+
this.context = this.describe
+
+ + + + +
+
this.context = this.describe
+
+describe 'Cat', ->
+  describe '#meow', ->
+    context 'hungry', ->
+      # cat codes
+
+    context 'going to the vet', ->
+      # moar cat codes
+
+ + + + +
+
this.context = this.describe
+
+describe 'Cat', ->
+  describe '#meow', ->
+    beforeEach ->
+      @cat = new Cat()
+
+    context 'hungry', ->
+      it 'should be a mournful meow', ->
+        @cat.state = -> Cat.HUNGRY
+
+        expect(@cat.meow()).toEqual("meeeyaow")
+
+    context 'going to the vet', ->
+      it 'should be an evil meow', ->
+        @cat.state = -> Cat.VET_PSYCHIC
+
+        expect(@cat.meow()).toEqual("raowwww")
+
+ + + + +
+
class this.Cat
+  @HUNGRY = 'hungry'
+  @VET_PSYCHIC = 'vet psychic'
+
+  meow: ->
+    switch this.state()
+      when Cat.HUNGRY
+        "meeeyaow"
+      when Cat.VET_PSYCHIC
+        "raowwww"
+
+ + + + +
+
2 spec, 0 failures
+
+ + + + +
+

Matchers

+ +
+
cat.meow.should == "meow"
+cat.should be_a_kind_of(Cat)
+cat.should_not be_hungry
+  # => cat.hungry?.should == false
+
+ + + + +
+
expect(cat.meow()).toEqual("meow")
+expect(cat.prototype).toEqual(Cat.prototype)
+expect(cat.isHungry()).not.toBeTruthy()
+
+ + + + +
+

Lots of built in matchers

+ +
toEqual(object)
+toBeTruthy()
+toBeFalsy()
+toBeGreaterThan()
+toBeLessThan()
+toBeUndefined()
+toContain()
+toMatch()
+
+ + + + +
+
expect(cat.isHungry()).not.toBeTruthy()
+
+ + + + +
+

Create your own matchers!

+ +
+
MyMatchers =
+  toBeHungry: ->
+    return @actual.isHungry() == true
+
+beforeEach ->
+  this.addMatchers(MyMatchers)
+
+describe 'Cat', ->
+  beforeEach ->
+    @cat = new Cat()
+
+  it 'should not be hungry', ->
+    expect(@cat).not.toBeHungry()
+
+ + + + +
+
describe
+it
+expect
+toSomething()
+beforeEach
+afterEach
+
+ + + + +
+

Jasmine == unit testing

+ +
+

+ +
+

No, this isn't a talk about integration testing

+ +
+

Testing the right things in your JavaScript unit tests

+ +
+

+ +
+

John behavior #2

+ +

Mock, stub, and spy on anything that should be handled in an integration test

+ +
describe 'John', ->
+  describe 'spec definitions', ->
+    it 'should keep unit tests as focused as possible', ->
+
+ + + + +
+

+ +
+
Feature: Cat Behaviors
+  Scenario: Hungry cats meow a particular way
+    Given I have a cat
+      And the cat is hungry
+    When the cat meows
+    Then the meow should sound like "meeyaow"
+
+ + + + +
+
class this.Cat
+  @FOOD_THRESHOLD = 20
+  @HUNGRY = 'hungry'
+
+  constructor: (@foodLevel = 30) ->
+
+  meow: ->
+    switch this.state()
+      when Cat.HUNGRY
+        "meeyaow"
+
+  state: ->
+    if @foodLevel < Cat.FOOD_THRESHOLD
+      Cat.HUNGRY
+
+ + + + +
+
describe 'Cat', ->
+  describe '#meow', ->
+    context 'hungry', ->
+      it 'should be a mournful meow', ->
+        cat = new Cat()
+        cat.foodLevel = 15
+
+        expect(cat.meow()).toEqual("meeeyaow")
+
+ + + + +
+

A perfectly cromulent test

+ +
+
class this.Cat
+  meow: ->
+    switch this.state() # <= dependent code executed
+      when Cat.HUNGRY
+        "meeyaow"
+
+ + + + +
+

Why make your unit tests fragile?

+ +
+
cat.foodLevel = 15
+  # do we care about food level in this test?
+    # all we care about is that the cat is hungry
+
+ + + + +
+
describe 'Cat', ->
+  describe '#meow', ->
+    describe 'hungry', ->
+      it 'should be a mournful meow', ->
+        cat = new Cat()
+        cat.state = -> Cat.HUNGRY
+          # ^^^ we don't care how state works,
+            # we just want a hungry cat
+
+        expect(cat.meow()).toEqual("meeeyaow")
+
+ + + + +
+

Instance Stubs in JavaScript

+ +

Just replace the method on the instance

+ +
class this.Cat
+  state: ->
+    # cat codes
+
+cat = new Cat()
+cat.state = -> "whatever"
+
+ + + + +
+

Stubs just return something when called

+ +
+

Mocks expect to be called

+ +
+

Test fails if all mocks are not called

+ +
+

Jasmine blurs the line a little

+ +
+

+ +
+

Spies work like mocks, but with additional abilities

+ +
+

+ +
+
class this.Cat
+  vocalProcessor: (speech) =>
+    if this.isAirborne()
+      this.modifyForAirborne(speech)
+    else
+      this.modifyForGround(speech)
+
+ + + + +
+
describe 'Cat#vocalProcessor', ->
+  speech = "speech"
+
+  beforeEach ->
+    @cat = new Cat()
+
+  context 'airborne', ->
+    beforeEach ->
+      spyOn(@cat, 'modifyForAirborne')
+      @cat.isAirborne = -> true
+
+    it 'should be modified for flight', ->
+      @cat.vocalProcessor(speech)
+      expect(@cat.modifyForAirborne).toHaveBeenCalledWith(speech)
+
+ + + + +
+

spyOn replaces a method on an instance with a spy method

+ +
spyOn(@cat, 'modifyForAirborne')
+
+ + + + +
+

Can return a value, run code, run the original code, or just wait to be called

+ +
+

Two basic ways to make sure a spy is called

+ +
+

toHaveBeenCalledWith(args...)

+ +

Called least once with the given parameters

+ +
expect(@cat.modifyForAirborne).toHaveBeenCalledWith(speech)
+
+ + + + +
+

toHaveBeenCalled()

+ +

Just called, no parameter check

+ +
expect(@cat.modifyForAirborne).toHaveBeenCalled()
+
+ + + + +
+

Instance Mocks/Spies in JavaScript

+ +

Use spyOn/toHaveBeenCalled matchers

+ +
class this.Cat
+  state: ->
+    # cat codes
+
+cat = new Cat()
+spyOn(cat, 'state')
+expect(cat.state).toHaveBeenCalled()
+
+ + + + +
+

spyOn works great with class-level stubs and mocks, too

+ +
+
class this.Cat
+  @generateFurColor: (base) ->
+    # magicks to make a fur color given a base
+
+  regrowFur: (damagedHairs) ->
+    for follicle in damagedHairs
+      follicle.regrow(Cat.generateFurColor(this.baseColor))
+
+ + + + +
+
Cat.generateFurColor = ->
+  "whoops i nuked this method for every other test"
+
+ + + + +
+
describe 'Cat#regrowFur', ->
+  color = 'color'
+
+  beforeEach ->
+    @cat = new Cat()
+    @follicle =
+      regrow: ->
+
+    @follicles = [ follicle ]
+
+    spyOn(Cat, 'generateFurColor').andReturn(color)
+    #           ^^^ original is replaced when done
+    spyOn(@follicle, 'regrow')
+
+  it 'should regrow', ->
+    @cat.regrowFur(@follicles)
+
+    expect(@follicle.regrow).toHaveBeenCalledWith(color)
+
+ + + + +
+

Class Stubs in JavaScript

+ +

Use spyOn to generate stubs so that the original code is replaced after the test

+ +
class this.Cat
+  @injectPsychicPowers: (cat) ->
+    # cat codes
+
+spyOn(Cat, 'injectPsychicPowers').andReturn(psychicCat)
+
+ + + + +
+

John behavior #3

+ +

If you have too many mocks/stubs/contexts, your code is too complex

+ +
describe 'John', ->
+  describe 'spec definitions', ->
+    it 'should obey the Law of Demeter as much as possible', ->
+    it 'should not smell too funny', ->
+
+ + + + +
+
describe 'Cat#fetch', ->
+  object = null
+
+  context 'a mouse', ->
+    beforeEach ->
+      object = new Mouse()
+
+    context 'fast mouse', ->
+      it 'should wear down the mouse', ->
+        # who
+
+    context 'slow mouse', ->
+      it 'should deliver a present to you', ->
+        # cares
+
+  context 'a ball', ->
+    beforeEach ->
+      object = new Ball()
+
+    context 'ball is bouncing', ->
+      it 'should cause the cat to leap', ->
+        # this
+
+    context 'ball is rolling', ->
+      it 'should cause the cat to slide on the floor', ->
+        # test
+
+  context 'a red dot', ->
+    laser = null
+
+    beforeEach ->
+      laser = new Laser()
+
+    context 'laser out of batteries', ->
+      it 'should not activate', ->
+        # is
+
+    context 'laser functioning', ->
+      it 'should activate, driving the cat insane', ->
+        # huge and unmaintainable and silly
+
+ + + + +
+

Sometimes you just need a big blob of unit tests

+ +
+
# fast and focused!
+
+describe 'Cat#respondsTo', ->
+  beforeEach ->
+    @cat = new Cat()
+
+  context 'successes', ->
+    it 'should respond', ->
+      for request in [ 'kitty kitty', 'pookums', 'hisshead' ]
+        expect(@cat.respondsTo(request)).toBeTruthy()
+
+ + + + +
+
# slow and synergistic!
+
+Scenario Outline: Successful responsiveness
+  Given I have a cat
+  When I call it with "<request>"
+  Then the cat should respond
+
+  Examples:
+    | request     |
+    | kitty kitty |
+    | pookums     |
+    | hisshead    |
+
+ + + + +
+

+ +
+

Find what works best for you and stick with it

+ +
+

...until you get sick of it, of course...

+ +
+

Using it in your project

+ +
+

Starts a Rack server for running Jasmine against your code

+ +
+

Really easy to plug into an existing Rails project

+ +
+

Want to make that run fast?

+ +
+

Use PhantomJS or jasmine-headless-webkit

+ +
+

Fast code running in a real browser

+ +
+

Evergreen

+ +
+

Jasminerice

+ +
+

Node.js

+ +
+

Pick your favorite!

+ +
+

Some miscellaneous hints and tips

+ +
+

Testing jQuery

+ +
+

Mocking and stubbing $.fn calls

+ +
+
this.containerWaiter = ->
+  $('#container').addClass('wait').append('<div class="waiting" />')
+
+ + + + +
+
$.fn.makeWait = ->
+  $(this).addClass('wait').append('<div class="waiting" />')
+  this
+
+ + + + +
+
this.containerWaiter = ->
+  $('#container').makeWait()
+
+ + + + +
+

jquery-jasmine

+ +
+
describe 'container', ->
+  beforeEach ->
+    setFixtures('<div id="container" />')
+
+  it 'should make it wait', ->
+    containerWaiter()
+    expect($('#container')).toHaveClass('wait')
+    expect($('#container')).toContain('div.waiting')
+
+ + + + +
+

+ +
+

+ +
+
describe '$.fn.makeWait', ->
+  it 'should make wait', ->
+    $div = $('<div />')
+    $div.makeWait()
+
+    expect($div).toHaveClass('wait')
+    expect($div).toContain('div.waiting')
+
+ + + + +
+
describe 'container', ->
+  beforeEach ->
+    setFixtures('<div id="container" />')
+    spyOn($.fn, 'makeWait')
+
+  it 'should make it wait', ->
+    containerWaiter()
+    expect($.fn.makeWait).toHaveBeenCalled()
+
+ + + + +
+

No longer testing jQuery, just testing for our code

+ +
+

Animations and other time-dependent things

+ +
+
class Cat
+  constructor: ->
+    @mood = "happy"
+
+  pet: ->
+    setTimeout(
+      -> @mood = "angry"
+      , 500
+    )
+
+ + + + +
+

Do you really need to test the setTimeout?

+ +
+
class Cat
+  constructor: ->
+    @mood = "happy"
+
+  pet: -> setTimeout(@makeAngry, 500)
+
+  makeAngry: => @mood = "angry"
+
+ + + + +
+

Use Jasmine's waitsFor and runs

+ +
+
describe 'cat moods', ->
+  it 'should change moods', ->
+    cat = new Cat()
+
+    # we want to know the cat's current mood
+    currentMood = cat.mood
+
+    #  start petting the cat
+    runs -> cat.pet()
+
+    # wait one second for the cat's mood to change
+    waitsFor(
+      ->
+        cat.mood != currentMood
+      , "Cat changed its mood",
+      1000
+    )
+
+    # expect the inevitable
+    runs ->
+      expect(cat.mood).toEqual('angry')
+
+ + + + +
+

So that's pretty much it.

+ +
+

Basic parts of Jasmine unit tests

+ +
describe
+it
+expect
+toSomething()
+beforeEach
+afterEach
+
+ + + + +
+

Mocking and stubbing

+ +
direct method replacement
+spyOn()
+toHaveBeenCalled()
+toHaveBeenCalledWith()
+
+ + + + +
+

Running Jasmine in your project

+ +
+

Hints and tips for JavaScript testing

+ +
waitsFor()
+runs()
+
+ + + + +
+

Any questions?

+ +
+

Thank you!

+ +

@johnbintz

+ +

GitHub

+ +
+ +
+ +