From a64763cab11138be62477a1006c458f5c7d1480f Mon Sep 17 00:00:00 2001 From: John Bintz Date: Fri, 23 Mar 2012 17:25:31 -0400 Subject: [PATCH] pre-gh pages creation --- _site/assets/application.js | 24 +- _site/index.html | 6781 +++++++++++++++++++++++++++-------- 2 files changed, 5211 insertions(+), 1594 deletions(-) diff --git a/_site/assets/application.js b/_site/assets/application.js index 07e801e..d124830 100644 --- a/_site/assets/application.js +++ b/_site/assets/application.js @@ -21,7 +21,6 @@ Attentive.Presentation = (function() { this.getCurrentSlide = __bind(this.getCurrentSlide, this); this.calculate = __bind(this.calculate, this); this.advanceTo = __bind(this.advanceTo, this); - this.isFile = __bind(this.isFile, this); this.advance = __bind(this.advance, this); this.handleKeyDown = __bind(this.handleKeyDown, this); this.handleClick = __bind(this.handleClick, this); @@ -50,9 +49,6 @@ Attentive.Presentation = (function() { Presentation.prototype.start = function() { var imageWait, _this = this; - if (!this.isFile()) { - window.addEventListener('popstate', this.handlePopState, false); - } this.timer.render(); document.addEventListener('click', this.handleClick, false); document.addEventListener('keydown', this.handleKeyDown, false); @@ -80,13 +76,11 @@ Attentive.Presentation = (function() { }; Presentation.prototype.slideFromLocation = function() { - var value; - value = this.isFile() ? location.hash : location.pathname; - return Number(value.substr(1)); + return Number(location.hash.substr(1)); }; Presentation.prototype.handlePopState = function(e) { - return this.advanceTo(e.state ? e.state.index : this.slideFromLocation()); + return this.advanceTo(this.slideFromLocation()); }; Presentation.prototype.handleClick = function(e) { @@ -98,9 +92,11 @@ Attentive.Presentation = (function() { case 72: return this.advanceTo(0); case 37: + case 33: return this.advance(-1); case 39: case 32: + case 34: return this.advance(); case 220: return this.timer.reset(); @@ -118,21 +114,11 @@ Attentive.Presentation = (function() { return this.advanceTo(Math.max(Math.min(this.currentSlide + offset, this.length - 1), 0)); }; - Presentation.prototype.isFile = function() { - return location.href.slice(0, 4) === 'file'; - }; - Presentation.prototype.advanceTo = function(index) { this.priorSlide = this.currentSlide; this.currentSlide = index || 0; this.calculate(); - if (this.isFile()) { - return location.hash = this.currentSlide; - } else { - return history.pushState({ - index: this.currentSlide - }, '', this.currentSlide); - } + return location.hash = this.currentSlide; }; Presentation.prototype.calculate = function() { diff --git a/_site/index.html b/_site/index.html index b29c00a..4a6d6c3 100644 --- a/_site/index.html +++ b/_site/index.html @@ -1,1580 +1,5211 @@ - + -Tea Time: A Beginner's Guide to Jasmine - - - - + + NameError at / + + + - -
-
-
- -
-

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')
-
-
- - - - -
-

Underscore.js mixins

- -

and other prototype mixin-style extensions

- -
-
CatLike =
-  catify: (name) ->
-    "meow meow #{name}"
-
-# mix in to the Underscore object
-_.mixin(CatLike)
-
-# use it
-_.catify("john") # => "meow meow john"
-
-
- - - - -
-
describe '_.catify', ->
-  it 'should catify', ->
-    expect(_.catify("hiss")).toEqual("meow meow hiss")
-
-
- - - - -
-

Eliminate the Underscore.js dependency

- -
-
describe 'CatLike', ->
-  beforeEach ->
-    @helper = {}
-
-    for method, code of CatLike
-      @helper[method] = code
-
-  describe '#catify', ->
-    it 'should catify', ->
-      expect(@helper.catify("hiss")).toEqual("meow meow hiss")
-
-
- - - - -
-

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

- -
- -
- - + +
+ + +
+

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:0x00000101971920>
rack.input
#<StringIO:0x00000100b3b568>
rack.logger
#<Logger:0x0000010099a100 @progname=nil, @level=1, @default_formatter=#<Logger::Formatter:0x0000010099a0d8 @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0x00000100999f20 @shift_size=nil, @shift_age=nil, @filename=nil, @dev=#<StringIO:0x00000100b3b658>, @mutex=#<Logger::LogDevice::LogDeviceMutex:0x00000100999e30 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0x00000100999c28>>>>
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.

+
+