├── lib
└── tasks
│ └── .gitkeep
├── public
├── favicon.ico
├── stylesheets
│ ├── .gitkeep
│ └── scaffold.css
├── .DS_Store
├── images
│ ├── rails.png
│ └── connect_facebook.png
├── javascripts
│ ├── application.js
│ ├── icanhaz.min.js
│ ├── underscore.min.js
│ ├── backbone.min.js
│ ├── icanhaz.js
│ ├── jquery_ujs.js
│ ├── json2.js
│ ├── underscore.js
│ └── backbone.js
├── robots.txt
├── 422.html
├── 404.html
└── 500.html
├── vendor
└── plugins
│ └── .gitkeep
├── .rvmrc
├── app
├── helpers
│ ├── home_helper.rb
│ ├── users_helper.rb
│ ├── sessions_helper.rb
│ └── application_helper.rb
├── views
│ ├── users
│ │ ├── new.html.erb
│ │ ├── edit.html.erb
│ │ ├── show.html.erb
│ │ ├── index.html.erb
│ │ └── _form.html.erb
│ ├── home
│ │ ├── authorize.html.erb
│ │ └── index.html.erb
│ └── layouts
│ │ └── application.html.erb
├── controllers
│ ├── home_controller.rb
│ ├── application_controller.rb
│ ├── sessions_controller.rb
│ └── users_controller.rb
└── models
│ └── user.rb
├── .gitignore
├── config
├── initializers
│ ├── backbone.rb
│ ├── mime_types.rb
│ ├── inflections.rb
│ ├── backtrace_silencers.rb
│ ├── session_store.rb
│ ├── secret_token.rb
│ └── omniauth.rb
├── environment.rb
├── boot.rb
├── locales
│ └── en.yml
├── database.yml
├── routes.rb
├── environments
│ ├── development.rb
│ ├── test.rb
│ └── production.rb
└── application.rb
├── .DS_Store
├── test
├── unit
│ ├── helpers
│ │ ├── home_helper_test.rb
│ │ ├── users_helper_test.rb
│ │ └── sessions_helper_test.rb
│ └── user_test.rb
├── functional
│ ├── sessions_controller_test.rb
│ ├── home_controller_test.rb
│ └── users_controller_test.rb
├── performance
│ └── browsing_test.rb
├── fixtures
│ └── users.yml
└── test_helper.rb
├── config.ru
├── db
├── migrate
│ ├── 20110626022944_change_column_type_users.rb
│ ├── 20110625201310_rename_columns_in_users.rb
│ └── 20110625194437_create_users.rb
├── seeds.rb
└── schema.rb
├── doc
└── README_FOR_APP
├── script
└── rails
├── Rakefile
├── Gemfile
├── Gemfile.lock
└── README
/lib/tasks/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/plugins/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/stylesheets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.rvmrc:
--------------------------------------------------------------------------------
1 | rvm use 1.9.2@fb-demo1 --create
2 |
--------------------------------------------------------------------------------
/app/helpers/home_helper.rb:
--------------------------------------------------------------------------------
1 | module HomeHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/users_helper.rb:
--------------------------------------------------------------------------------
1 | module UsersHelper
2 | end
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle
2 | db/*.sqlite3
3 | log/*.log
4 | tmp/
5 |
--------------------------------------------------------------------------------
/app/helpers/sessions_helper.rb:
--------------------------------------------------------------------------------
1 | module SessionsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/config/initializers/backbone.rb:
--------------------------------------------------------------------------------
1 | ActiveRecord::Base.include_root_in_json = false
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gertig/facebook-invitations-demo/HEAD/.DS_Store
--------------------------------------------------------------------------------
/public/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gertig/facebook-invitations-demo/HEAD/public/.DS_Store
--------------------------------------------------------------------------------
/public/images/rails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gertig/facebook-invitations-demo/HEAD/public/images/rails.png
--------------------------------------------------------------------------------
/app/views/users/new.html.erb:
--------------------------------------------------------------------------------
1 |
New user
2 |
3 | <%= render 'form' %>
4 |
5 | <%= link_to 'Back', users_path %>
6 |
--------------------------------------------------------------------------------
/test/unit/helpers/home_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class HomeHelperTest < ActionView::TestCase
4 | end
5 |
--------------------------------------------------------------------------------
/test/unit/helpers/users_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersHelperTest < ActionView::TestCase
4 | end
5 |
--------------------------------------------------------------------------------
/test/unit/helpers/sessions_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsHelperTest < ActionView::TestCase
4 | end
5 |
--------------------------------------------------------------------------------
/public/images/connect_facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gertig/facebook-invitations-demo/HEAD/public/images/connect_facebook.png
--------------------------------------------------------------------------------
/app/views/home/authorize.html.erb:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/views/users/edit.html.erb:
--------------------------------------------------------------------------------
1 | Editing user
2 |
3 | <%= render 'form' %>
4 |
5 | <%= link_to 'Show', @user %> |
6 | <%= link_to 'Back', users_path %>
7 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run FbDemo1::Application
5 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the rails application
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the rails application
5 | FbDemo1::Application.initialize!
6 |
--------------------------------------------------------------------------------
/public/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // Place your application-specific JavaScript functions and classes here
2 | // This file is automatically included by javascript_include_tag :defaults
3 |
--------------------------------------------------------------------------------
/test/unit/user_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UserTest < ActiveSupport::TestCase
4 | # Replace this with your real tests.
5 | test "the truth" do
6 | assert true
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 |
3 | # Set up gems listed in the Gemfile.
4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
5 |
6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
7 |
--------------------------------------------------------------------------------
/db/migrate/20110626022944_change_column_type_users.rb:
--------------------------------------------------------------------------------
1 | class ChangeColumnTypeUsers < ActiveRecord::Migration
2 | def self.up
3 | change_column(:users, :fb_uid, :string)
4 | end
5 |
6 | def self.down
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/doc/README_FOR_APP:
--------------------------------------------------------------------------------
1 | Use this README file to introduce your application and point to useful places in the API for learning more.
2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
3 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-Agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/test/functional/sessions_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsControllerTest < ActionController::TestCase
4 | # Replace this with your real tests.
5 | test "the truth" do
6 | assert true
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/test/functional/home_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class HomeControllerTest < ActionController::TestCase
4 | test "should get index" do
5 | get :index
6 | assert_response :success
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 | # Mime::Type.register_alias "text/html", :iphone
6 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Sample localization file for English. Add more files in this directory for other locales.
2 | # See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3 |
4 | en:
5 | hello: "Hello world"
6 |
--------------------------------------------------------------------------------
/app/controllers/home_controller.rb:
--------------------------------------------------------------------------------
1 | class HomeController < ApplicationController
2 |
3 | def index
4 | @users = User.all
5 | end
6 |
7 | def authorize
8 | respond_to do |format|
9 | format.html # authorize.html.erb
10 | end
11 | end
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20110625201310_rename_columns_in_users.rb:
--------------------------------------------------------------------------------
1 | class RenameColumnsInUsers < ActiveRecord::Migration
2 | def self.up
3 | #rename_column(:users, :fb_id, :fb_uid)
4 | #rename_column(:users, :fb_access_token, :fb_token)
5 | end
6 |
7 | def self.down
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/performance/browsing_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 | require 'rails/performance_test_help'
3 |
4 | # Profiling results for each test method are written to tmp/performance.
5 | class BrowsingTest < ActionDispatch::PerformanceTest
6 | def test_homepage
7 | get '/'
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Awesomeness
5 | <%= stylesheet_link_tag :all %>
6 | <%= javascript_include_tag :defaults %>
7 | <%= csrf_meta_tag %>
8 |
9 |
10 |
11 | <%= yield %>
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/script/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3 |
4 | APP_PATH = File.expand_path('../../config/application', __FILE__)
5 | require File.expand_path('../../config/boot', __FILE__)
6 | require 'rails/commands'
7 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # Add your own tasks in files placed in lib/tasks ending in .rake,
2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 |
4 | require File.expand_path('../config/application', __FILE__)
5 | require 'rake/dsl_definition'
6 | require 'rake'
7 |
8 | FbDemo1::Application.load_tasks
9 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | protect_from_forgery
3 | helper_method :current_user #Makes it available to the views
4 |
5 | private
6 |
7 | def current_user
8 | @current_user ||= User.find(session[:user_id]) if session[:user_id]
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
7 | # Mayor.create(:name => 'Daley', :city => cities.first)
8 |
--------------------------------------------------------------------------------
/test/fixtures/users.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 |
3 | one:
4 | first_name: MyString
5 | last_name: MyString
6 | email: MyString
7 | number_of_friends: 1
8 | fb_uid: 1
9 | fb_token: MyString
10 |
11 | two:
12 | first_name: MyString
13 | last_name: MyString
14 | email: MyString
15 | number_of_friends: 1
16 | fb_uid: 1
17 | fb_token: MyString
18 |
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | class User < ActiveRecord::Base
2 |
3 | def self.create_with_omniauth(auth)
4 | create! do |user|
5 | user.first_name = auth["user_info"]["first_name"]
6 | user.last_name = auth["user_info"]["last_name"]
7 | user.email = auth["user_info"]["email"]
8 | user.fb_uid = auth["uid"]
9 | user.fb_token = auth["credentials"]["token"]
10 | end
11 | end
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format
4 | # (all these examples are active by default):
5 | # ActiveSupport::Inflector.inflections do |inflect|
6 | # inflect.plural /^(ox)$/i, '\1en'
7 | # inflect.singular /^(ox)en/i, '\1'
8 | # inflect.irregular 'person', 'people'
9 | # inflect.uncountable %w( fish sheep )
10 | # end
11 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/db/migrate/20110625194437_create_users.rb:
--------------------------------------------------------------------------------
1 | class CreateUsers < ActiveRecord::Migration
2 | def self.up
3 | create_table :users do |t|
4 | t.string :first_name
5 | t.string :last_name
6 | t.string :email
7 | t.integer :number_of_friends, :default => 0
8 | t.integer :fb_uid
9 | t.string :fb_token
10 |
11 | t.timestamps
12 | end
13 | end
14 |
15 | def self.down
16 | drop_table :users
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'http://rubygems.org'
2 |
3 | gem 'rails', '3.0.9'
4 |
5 | # Bundle edge Rails instead:
6 | # gem 'rails', :git => 'git://github.com/rails/rails.git'
7 |
8 |
9 | gem 'sqlite3'
10 | gem 'jquery-rails'
11 | gem 'backbonejs-rails', "~> 0.0.3"
12 | gem 'omniauth'
13 | #gem 'koala'
14 |
15 | group :development do
16 | #gem "rake", "0.9.2"
17 | gem "mongrel", "~> 1.2.0.pre2"
18 | end
19 |
20 | group :production do
21 | #gem 'rake', '~> 0.8.7'
22 | end
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | FbDemo1::Application.config.session_store :cookie_store, :key => '_fb-demo1_session'
4 |
5 | # Use the database for sessions instead of the cookie-based default,
6 | # which shouldn't be used to store highly confidential information
7 | # (create the session table with "rails generate session_migration")
8 | # FbDemo1::Application.config.session_store :active_record_store
9 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RAILS_ENV"] = "test"
2 | require File.expand_path('../../config/environment', __FILE__)
3 | require 'rails/test_help'
4 |
5 | class ActiveSupport::TestCase
6 | # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
7 | #
8 | # Note: You'll currently still have to declare fixtures explicitly in integration tests
9 | # -- they do not yet inherit this setting
10 | fixtures :all
11 |
12 | # Add more helper methods to be used by all tests here...
13 | end
14 |
--------------------------------------------------------------------------------
/app/controllers/sessions_controller.rb:
--------------------------------------------------------------------------------
1 | class SessionsController < ApplicationController
2 |
3 |
4 | def create
5 | auth = request.env["omniauth.auth"]
6 | user = User.find_by_fb_uid_and_fb_token(auth["uid"], auth["credentials"]["token"]) || User.create_with_omniauth(auth)
7 | session[:user_id] = user.id
8 |
9 | redirect_to root_url, :notice => "Signed In"
10 | end
11 |
12 | def destroy
13 | session[:user_id] = nil
14 |
15 | redirect_to root_url, :notice => "Signed Out"
16 | end
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/config/initializers/secret_token.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 | # Make sure the secret is at least 30 characters and all random,
6 | # no regular words or you'll be exposed to dictionary attacks.
7 | FbDemo1::Application.config.secret_token = 'b22c3b54f6c0d8e6017ed33755e58ae46370236ae59ccaaf5b7b0d35a49e016e0bc19c446e0828d7491c1f1c1ee875732835346c09abd67f118d08f7061f9e7a'
8 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | development:
4 | adapter: sqlite3
5 | database: db/development.sqlite3
6 | pool: 5
7 | timeout: 5000
8 |
9 | # Warning: The database defined as "test" will be erased and
10 | # re-generated from your development database when you run "rake".
11 | # Do not set this db to the same as development or production.
12 | test:
13 | adapter: sqlite3
14 | database: db/test.sqlite3
15 | pool: 5
16 | timeout: 5000
17 |
18 | production:
19 | adapter: sqlite3
20 | database: db/production.sqlite3
21 | pool: 5
22 | timeout: 5000
23 |
--------------------------------------------------------------------------------
/app/views/users/show.html.erb:
--------------------------------------------------------------------------------
1 | <%= notice %>
2 |
3 |
4 | First name:
5 | <%= @user.first_name %>
6 |
7 |
8 |
9 | Last name:
10 | <%= @user.last_name %>
11 |
12 |
13 |
14 | Email:
15 | <%= @user.email %>
16 |
17 |
18 |
19 | Number of friends:
20 | <%= @user.number_of_friends %>
21 |
22 |
23 |
24 | Fb:
25 | <%= @user.fb_uid %>
26 |
27 |
28 |
29 | Fb access token:
30 | <%= @user.fb_token %>
31 |
32 |
33 |
34 | <%= link_to 'Edit', edit_user_path(@user) %> |
35 | <%= link_to 'Back', users_path %>
36 |
--------------------------------------------------------------------------------
/app/views/users/index.html.erb:
--------------------------------------------------------------------------------
1 | Listing users
2 |
3 |
4 |
5 | | First name |
6 | Last name |
7 | Email |
8 | Fb uid |
9 | |
10 | |
11 | |
12 |
13 |
14 | <% @users.each do |user| %>
15 |
16 | | <%= user.first_name %> |
17 | <%= user.last_name %> |
18 | <%= user.email %> |
19 | <%= user.fb_uid %> |
20 | <%= link_to 'Show', user %> |
21 | <%= link_to 'Edit', edit_user_path(user) %> |
22 | <%= link_to 'Destroy', user, :confirm => 'Are you sure?', :method => :delete %> |
23 |
24 | <% end %>
25 |
26 |
27 |
28 |
29 | <%= link_to 'New User', new_user_path %>
30 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | FbDemo1::Application.routes.draw do
2 | get "home/index"
3 | post "home/authorize" #The route that Facebook will post to
4 |
5 | resources :users
6 |
7 | match "/auth/:provider/callback" => "sessions#create"
8 | match "/signout" => "sessions#destroy", :as => :signout #:as => :signout means you can use signout_path to access this
9 |
10 | # You can have the root of your site routed with "root"
11 | # just remember to delete public/index.html.
12 | root :to => "home#index"
13 |
14 | # See how all your routes lay out with "rake routes"
15 |
16 | # This is a legacy wild controller route that's not recommended for RESTful applications.
17 | # Note: This route will make all actions in every controller accessible via GET requests.
18 | # match ':controller(/:action(/:id(.:format)))'
19 | end
20 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The change you wanted was rejected.
23 |
Maybe you tried to change something you didn't have access to.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
The page you were looking for doesn't exist.
23 |
You may have mistyped the address or the page may have moved.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
17 |
18 |
19 |
20 |
21 |
22 |
We're sorry, but something went wrong.
23 |
We've been notified about this issue and we'll take a look at it shortly.
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | FbDemo1::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the webserver when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Log error messages when you accidentally call methods on nil.
10 | config.whiny_nils = true
11 |
12 | # Show full error reports and disable caching
13 | config.consider_all_requests_local = true
14 | config.action_view.debug_rjs = true
15 | config.action_controller.perform_caching = false
16 |
17 | # Don't care if the mailer can't send
18 | config.action_mailer.raise_delivery_errors = false
19 |
20 | # Print deprecation notices to the Rails logger
21 | config.active_support.deprecation = :log
22 |
23 | # Only use best-standards-support built into browsers
24 | config.action_dispatch.best_standards_support = :builtin
25 | end
26 |
27 |
--------------------------------------------------------------------------------
/db/schema.rb:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from the current state of the database. Instead
2 | # of editing this file, please use the migrations feature of Active Record to
3 | # incrementally modify your database, and then regenerate this schema definition.
4 | #
5 | # Note that this schema.rb definition is the authoritative source for your
6 | # database schema. If you need to create the application database on another
7 | # system, you should be using db:schema:load, not running all the migrations
8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 | # you'll amass, the slower it'll run and the greater likelihood for issues).
10 | #
11 | # It's strongly recommended to check this file into your version control system.
12 |
13 | ActiveRecord::Schema.define(:version => 20110626022944) do
14 |
15 | create_table "users", :force => true do |t|
16 | t.string "first_name"
17 | t.string "last_name"
18 | t.string "email"
19 | t.integer "number_of_friends", :default => 0
20 | t.string "fb_uid"
21 | t.string "fb_token"
22 | t.datetime "created_at"
23 | t.datetime "updated_at"
24 | end
25 |
26 | end
27 |
--------------------------------------------------------------------------------
/app/views/users/_form.html.erb:
--------------------------------------------------------------------------------
1 | <%= form_for(@user) do |f| %>
2 | <% if @user.errors.any? %>
3 |
4 |
<%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:
5 |
6 |
7 | <% @user.errors.full_messages.each do |msg| %>
8 | - <%= msg %>
9 | <% end %>
10 |
11 |
12 | <% end %>
13 |
14 |
15 | <%= f.label :first_name %>
16 | <%= f.text_field :first_name %>
17 |
18 |
19 | <%= f.label :last_name %>
20 | <%= f.text_field :last_name %>
21 |
22 |
23 | <%= f.label :email %>
24 | <%= f.text_field :email %>
25 |
26 |
27 | <%= f.label :number_of_friends %>
28 | <%= f.text_field :number_of_friends %>
29 |
30 |
31 | <%= f.label :fb_uid %>
32 | <%= f.text_field :fb_uid %>
33 |
34 |
35 | <%= f.label :fb_token %>
36 | <%= f.text_field :fb_token %>
37 |
38 |
39 | <%= f.submit %>
40 |
41 | <% end %>
42 |
--------------------------------------------------------------------------------
/test/functional/users_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersControllerTest < ActionController::TestCase
4 | setup do
5 | @user = users(:one)
6 | end
7 |
8 | test "should get index" do
9 | get :index
10 | assert_response :success
11 | assert_not_nil assigns(:users)
12 | end
13 |
14 | test "should get new" do
15 | get :new
16 | assert_response :success
17 | end
18 |
19 | test "should create user" do
20 | assert_difference('User.count') do
21 | post :create, :user => @user.attributes
22 | end
23 |
24 | assert_redirected_to user_path(assigns(:user))
25 | end
26 |
27 | test "should show user" do
28 | get :show, :id => @user.to_param
29 | assert_response :success
30 | end
31 |
32 | test "should get edit" do
33 | get :edit, :id => @user.to_param
34 | assert_response :success
35 | end
36 |
37 | test "should update user" do
38 | put :update, :id => @user.to_param, :user => @user.attributes
39 | assert_redirected_to user_path(assigns(:user))
40 | end
41 |
42 | test "should destroy user" do
43 | assert_difference('User.count', -1) do
44 | delete :destroy, :id => @user.to_param
45 | end
46 |
47 | assert_redirected_to users_path
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/app/views/home/index.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
Awesome People
3 |
4 | <% if current_user %>
5 | Hello, <%= current_user.first_name %> | <%= link_to "Sign out", signout_path %>
6 | <% else %>
7 | <%= link_to "Login With Facebook", "/auth/facebook", :class => "connect_with_facebook_button" %>
8 |
Please, connect ONLY if you are Awesome.
9 | <% end %>
10 |
11 |
12 | <% if current_user %>
13 |
14 |
<%= link_to "Invite Your Facebook Friends", "#", :id => "invite_fb_friends" %>
15 |
16 |
17 |
18 |
19 |
20 |
34 |
35 | <% end %>
36 |
37 |
38 |
39 |
40 | <% @users.each do |user| %>
41 |
42 | | <%= user.first_name %> <%= user.last_name %> is Awesome! |
43 |
44 | <% end %>
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | FbDemo1::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Log error messages when you accidentally call methods on nil.
11 | config.whiny_nils = true
12 |
13 | # Show full error reports and disable caching
14 | config.consider_all_requests_local = true
15 | config.action_controller.perform_caching = false
16 |
17 | # Raise exceptions instead of rendering exception templates
18 | config.action_dispatch.show_exceptions = false
19 |
20 | # Disable request forgery protection in test environment
21 | config.action_controller.allow_forgery_protection = false
22 |
23 | # Tell Action Mailer not to deliver emails to the real world.
24 | # The :test delivery method accumulates sent emails in the
25 | # ActionMailer::Base.deliveries array.
26 | config.action_mailer.delivery_method = :test
27 |
28 | # Use SQL instead of Active Record's schema dumper when creating the test database.
29 | # This is necessary if your schema can't be completely dumped by the schema dumper,
30 | # like if you have constraints or database-specific column types
31 | # config.active_record.schema_format = :sql
32 |
33 | # Print deprecation notices to the stderr
34 | config.active_support.deprecation = :stderr
35 | end
36 |
--------------------------------------------------------------------------------
/config/initializers/omniauth.rb:
--------------------------------------------------------------------------------
1 | #APP_ID, APP_SECRET
2 | Rails.application.config.middleware.use OmniAuth::Builder do
3 | provider :facebook , '138781652866563', '5825f4b91f3ecce46efebca3df717aa2', :iframe => true,
4 | :scope => 'email, user_about_me,user_activities,user_birthday,user_education_history,
5 | user_events,user_groups,user_hometown,user_interests,user_likes, user_location,
6 | user_religion_politics,
7 | user_status,user_work_history,
8 | publish_stream, offline_access,
9 | friends_about_me'
10 |
11 | # friends_activities,friends_birthday,friends_education_history,friends_events,
12 | # friends_groups,friends_hometown,friends_interests,friends_likes,friends_location,
13 | # friends_photo_video_tags,friends_photos,friends_relationships,
14 | # friends_relationship_details,friends_religion_politics,friends_status,
15 | # friends_work_history
16 |
17 | # user_relationships, user_relationship_details,
18 | # user_photo_video_tags,user_photos,
19 | # publish_checkins,manage_pages,
20 | # create_event,rsvp_event,sms,read_friendlists,read_insights,read_mailbox,
21 | # read_requests,read_stream,xmpp_login,ads_management,
22 | # user_checkins,user_videos,user_website, user_notes,user_online_presence,user_address,user_mobile_phone
23 | # friends_notes,friends_online_presence, friends_videos,friends_website, manage_friendlists,friends_checkins
24 |
25 | #Adding, :iframe => true allows a Facebook App to redirect out of Facebook for authentication
26 | end
--------------------------------------------------------------------------------
/config/environments/production.rb:
--------------------------------------------------------------------------------
1 | FbDemo1::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb
3 |
4 | # The production environment is meant for finished, "live" apps.
5 | # Code is not reloaded between requests
6 | config.cache_classes = true
7 |
8 | # Full error reports are disabled and caching is turned on
9 | config.consider_all_requests_local = false
10 | config.action_controller.perform_caching = true
11 |
12 | # Specifies the header that your server uses for sending files
13 | config.action_dispatch.x_sendfile_header = "X-Sendfile"
14 |
15 | # For nginx:
16 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
17 |
18 | # If you have no front-end server that supports something like X-Sendfile,
19 | # just comment this out and Rails will serve the files
20 |
21 | # See everything in the log (default is :info)
22 | # config.log_level = :debug
23 |
24 | # Use a different logger for distributed setups
25 | # config.logger = SyslogLogger.new
26 |
27 | # Use a different cache store in production
28 | # config.cache_store = :mem_cache_store
29 |
30 | # Disable Rails's static asset server
31 | # In production, Apache or nginx will already do this
32 | config.serve_static_assets = false
33 |
34 | # Enable serving of images, stylesheets, and javascripts from an asset server
35 | # config.action_controller.asset_host = "http://assets.example.com"
36 |
37 | # Disable delivery errors, bad email addresses will be ignored
38 | # config.action_mailer.raise_delivery_errors = false
39 |
40 | # Enable threaded mode
41 | # config.threadsafe!
42 |
43 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
44 | # the I18n.default_locale when a translation can not be found)
45 | config.i18n.fallbacks = true
46 |
47 | # Send deprecation notices to registered listeners
48 | config.active_support.deprecation = :notify
49 | end
50 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 |
5 | # If you have a Gemfile, require the gems listed there, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(:default, Rails.env) if defined?(Bundler)
8 |
9 | module FbDemo1
10 | class Application < Rails::Application
11 | # Settings in config/environments/* take precedence over those specified here.
12 | # Application configuration should go into files in config/initializers
13 | # -- all .rb files in that directory are automatically loaded.
14 |
15 | # Custom directories with classes and modules you want to be autoloadable.
16 | # config.autoload_paths += %W(#{config.root}/extras)
17 |
18 | # Only load the plugins named here, in the order given (default is alphabetical).
19 | # :all can be used as a placeholder for all plugins not explicitly named.
20 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
21 |
22 | # Activate observers that should always be running.
23 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
24 |
25 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
26 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
27 | # config.time_zone = 'Central Time (US & Canada)'
28 |
29 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
30 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
31 | # config.i18n.default_locale = :de
32 |
33 | # JavaScript files you want as :defaults (application.js is always included).
34 | # config.action_view.javascript_expansions[:defaults] = %w(jquery rails)
35 |
36 | # Configure the default encoding used in templates for Ruby 1.9.
37 | config.encoding = "utf-8"
38 |
39 | # Configure sensitive parameters which will be filtered from the log file.
40 | config.filter_parameters += [:password]
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/public/stylesheets/scaffold.css:
--------------------------------------------------------------------------------
1 | /* FACEBOOK BUTTON */
2 | a { padding: 0; magin: 0; }
3 | a.connect_with_facebook_button{
4 | display:block; width:250px; height:50px; margin: 10px auto 10px;
5 | text-indent:-10000px;
6 | background:transparent url("/images/connect_facebook.png") top left no-repeat;
7 | }
8 |
9 | /* * { outline: 1px solid #336699;} */
10 |
11 | a.connect_with_facebook_button:hover{background-position:0 -50px}
12 |
13 | div#facebook_app {
14 | width: 480px;
15 | height: 300px;
16 | background: #CCDDEE;
17 | border: 1px solid #336699;
18 | border-top: 0px;
19 | margin: 0px auto;
20 | padding: 20px;
21 | }
22 |
23 | div#nav, div#friends {
24 | margin: 20px 0px;
25 | width: 100%;
26 | text-align: center;
27 | }
28 |
29 | h2, h3 {
30 | color: #336699;
31 | width: 100%;
32 | text-align: center;
33 | margin-top: 10px;
34 | }
35 |
36 | body { background-color: #fff; color: #333; }
37 |
38 | body, p, ol, ul, td {
39 | font-family: verdana, arial, helvetica, sans-serif;
40 | font-size: 13px;
41 | line-height: 18px;
42 | }
43 |
44 | pre {
45 | background-color: #eee;
46 | padding: 10px;
47 | font-size: 11px;
48 | }
49 |
50 | a { color: #000; }
51 | a:visited { color: #666; }
52 | /* a:hover { color: #fff; background-color:#000; } */
53 |
54 | div.field, div.actions {
55 | margin-bottom: 10px;
56 | }
57 |
58 | #notice {
59 | color: green;
60 | }
61 |
62 | .field_with_errors {
63 | padding: 2px;
64 | background-color: red;
65 | display: table;
66 | }
67 |
68 | #error_explanation {
69 | width: 450px;
70 | border: 2px solid red;
71 | padding: 7px;
72 | padding-bottom: 0;
73 | margin-bottom: 20px;
74 | background-color: #f0f0f0;
75 | }
76 |
77 | #error_explanation h2 {
78 | text-align: left;
79 | font-weight: bold;
80 | padding: 5px 5px 5px 15px;
81 | font-size: 12px;
82 | margin: -7px;
83 | margin-bottom: 0px;
84 | background-color: #c00;
85 | color: #fff;
86 | }
87 |
88 | #error_explanation ul li {
89 | font-size: 12px;
90 | list-style: square;
91 | }
92 |
93 | body, html { padding: 0px; margin: 0px;}
94 |
--------------------------------------------------------------------------------
/app/controllers/users_controller.rb:
--------------------------------------------------------------------------------
1 | class UsersController < ApplicationController
2 | # GET /users
3 | # GET /users.xml
4 | def index
5 | @users = User.all
6 |
7 | respond_to do |format|
8 | format.html # index.html.erb
9 | format.xml { render :xml => @users }
10 | end
11 | end
12 |
13 | # GET /users/1
14 | # GET /users/1.xml
15 | def show
16 | @user = User.find(params[:id])
17 |
18 | respond_to do |format|
19 | format.html # show.html.erb
20 | format.xml { render :xml => @user }
21 | end
22 | end
23 |
24 | # GET /users/new
25 | # GET /users/new.xml
26 | def new
27 | @user = User.new
28 |
29 | respond_to do |format|
30 | format.html # new.html.erb
31 | format.xml { render :xml => @user }
32 | end
33 | end
34 |
35 | # GET /users/1/edit
36 | def edit
37 | @user = User.find(params[:id])
38 | end
39 |
40 | # POST /users
41 | # POST /users.xml
42 | def create
43 | @user = User.new(params[:user])
44 |
45 | respond_to do |format|
46 | if @user.save
47 | format.html { redirect_to(@user, :notice => 'User was successfully created.') }
48 | format.xml { render :xml => @user, :status => :created, :location => @user }
49 | else
50 | format.html { render :action => "new" }
51 | format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
52 | end
53 | end
54 | end
55 |
56 | # PUT /users/1
57 | # PUT /users/1.xml
58 | def update
59 | @user = User.find(params[:id])
60 |
61 | respond_to do |format|
62 | if @user.update_attributes(params[:user])
63 | format.html { redirect_to(@user, :notice => 'User was successfully updated.') }
64 | format.xml { head :ok }
65 | else
66 | format.html { render :action => "edit" }
67 | format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
68 | end
69 | end
70 | end
71 |
72 | # DELETE /users/1
73 | # DELETE /users/1.xml
74 | def destroy
75 | @user = User.find(params[:id])
76 | @user.destroy
77 |
78 | respond_to do |format|
79 | format.html { redirect_to(users_url) }
80 | format.xml { head :ok }
81 | end
82 | end
83 | end
84 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: http://rubygems.org/
3 | specs:
4 | abstract (1.0.0)
5 | actionmailer (3.0.9)
6 | actionpack (= 3.0.9)
7 | mail (~> 2.2.19)
8 | actionpack (3.0.9)
9 | activemodel (= 3.0.9)
10 | activesupport (= 3.0.9)
11 | builder (~> 2.1.2)
12 | erubis (~> 2.6.6)
13 | i18n (~> 0.5.0)
14 | rack (~> 1.2.1)
15 | rack-mount (~> 0.6.14)
16 | rack-test (~> 0.5.7)
17 | tzinfo (~> 0.3.23)
18 | activemodel (3.0.9)
19 | activesupport (= 3.0.9)
20 | builder (~> 2.1.2)
21 | i18n (~> 0.5.0)
22 | activerecord (3.0.9)
23 | activemodel (= 3.0.9)
24 | activesupport (= 3.0.9)
25 | arel (~> 2.0.10)
26 | tzinfo (~> 0.3.23)
27 | activeresource (3.0.9)
28 | activemodel (= 3.0.9)
29 | activesupport (= 3.0.9)
30 | activesupport (3.0.9)
31 | addressable (2.2.4)
32 | arel (2.0.10)
33 | backbonejs-rails (0.0.3)
34 | curb (~> 0.7.15)
35 | railties (~> 3.0)
36 | thor (~> 0.14)
37 | builder (2.1.2)
38 | curb (0.7.15)
39 | daemons (1.0.10)
40 | erubis (2.6.6)
41 | abstract (>= 1.0.0)
42 | faraday (0.6.1)
43 | addressable (~> 2.2.4)
44 | multipart-post (~> 1.1.0)
45 | rack (>= 1.1.0, < 2)
46 | gem_plugin (0.2.3)
47 | i18n (0.5.0)
48 | jquery-rails (1.0.12)
49 | railties (~> 3.0)
50 | thor (~> 0.14)
51 | mail (2.2.19)
52 | activesupport (>= 2.3.6)
53 | i18n (>= 0.4.0)
54 | mime-types (~> 1.16)
55 | treetop (~> 1.4.8)
56 | mime-types (1.16)
57 | mongrel (1.2.0.pre2)
58 | daemons (~> 1.0.10)
59 | gem_plugin (~> 0.2.3)
60 | multi_json (1.0.3)
61 | multi_xml (0.2.2)
62 | multipart-post (1.1.2)
63 | net-ldap (0.2.2)
64 | nokogiri (1.4.6)
65 | oa-basic (0.2.6)
66 | oa-core (= 0.2.6)
67 | rest-client (~> 1.6.0)
68 | oa-core (0.2.6)
69 | oa-enterprise (0.2.6)
70 | addressable (= 2.2.4)
71 | net-ldap (~> 0.2.2)
72 | nokogiri (~> 1.4.2)
73 | oa-core (= 0.2.6)
74 | pyu-ruby-sasl (~> 0.0.3.1)
75 | rubyntlm (~> 0.1.1)
76 | oa-more (0.2.6)
77 | multi_json (~> 1.0.0)
78 | oa-core (= 0.2.6)
79 | rest-client (~> 1.6.0)
80 | oa-oauth (0.2.6)
81 | faraday (~> 0.6.1)
82 | multi_json (~> 1.0.0)
83 | multi_xml (~> 0.2.2)
84 | oa-core (= 0.2.6)
85 | oauth (~> 0.4.0)
86 | oauth2 (~> 0.4.1)
87 | oa-openid (0.2.6)
88 | oa-core (= 0.2.6)
89 | rack-openid (~> 1.3.1)
90 | ruby-openid-apps-discovery (~> 1.2.0)
91 | oauth (0.4.4)
92 | oauth2 (0.4.1)
93 | faraday (~> 0.6.1)
94 | multi_json (>= 0.0.5)
95 | omniauth (0.2.6)
96 | oa-basic (= 0.2.6)
97 | oa-core (= 0.2.6)
98 | oa-enterprise (= 0.2.6)
99 | oa-more (= 0.2.6)
100 | oa-oauth (= 0.2.6)
101 | oa-openid (= 0.2.6)
102 | polyglot (0.3.1)
103 | pyu-ruby-sasl (0.0.3.3)
104 | rack (1.2.3)
105 | rack-mount (0.6.14)
106 | rack (>= 1.0.0)
107 | rack-openid (1.3.1)
108 | rack (>= 1.1.0)
109 | ruby-openid (>= 2.1.8)
110 | rack-test (0.5.7)
111 | rack (>= 1.0)
112 | rails (3.0.9)
113 | actionmailer (= 3.0.9)
114 | actionpack (= 3.0.9)
115 | activerecord (= 3.0.9)
116 | activeresource (= 3.0.9)
117 | activesupport (= 3.0.9)
118 | bundler (~> 1.0)
119 | railties (= 3.0.9)
120 | railties (3.0.9)
121 | actionpack (= 3.0.9)
122 | activesupport (= 3.0.9)
123 | rake (>= 0.8.7)
124 | rdoc (~> 3.4)
125 | thor (~> 0.14.4)
126 | rake (0.9.2)
127 | rdoc (3.6.1)
128 | rest-client (1.6.3)
129 | mime-types (>= 1.16)
130 | ruby-openid (2.1.8)
131 | ruby-openid-apps-discovery (1.2.0)
132 | ruby-openid (>= 2.1.7)
133 | rubyntlm (0.1.1)
134 | sqlite3 (1.3.3)
135 | thor (0.14.6)
136 | treetop (1.4.9)
137 | polyglot (>= 0.3.1)
138 | tzinfo (0.3.28)
139 |
140 | PLATFORMS
141 | ruby
142 |
143 | DEPENDENCIES
144 | backbonejs-rails (~> 0.0.3)
145 | jquery-rails
146 | mongrel (~> 1.2.0.pre2)
147 | omniauth
148 | rails (= 3.0.9)
149 | sqlite3
150 |
--------------------------------------------------------------------------------
/public/javascripts/icanhaz.min.js:
--------------------------------------------------------------------------------
1 | (function(i){var n=function(){var f=function(){};f.prototype={otag:"{{",ctag:"}}",pragmas:{},buffer:[],pragmas_implemented:{"IMPLICIT-ITERATOR":true},context:{},render:function(a,b,c,d){if(!d){this.context=b;this.buffer=[]}if(!this.includes("",a))if(d)return a;else{this.send(a);return}a=this.render_pragmas(a);a=this.render_section(a,b,c);if(d)return this.render_tags(a,b,c,d);this.render_tags(a,b,c,d)},send:function(a){a!=""&&this.buffer.push(a)},render_pragmas:function(a){if(!this.includes("%",a))return a;
2 | var b=this;return a.replace(RegExp(this.otag+"%([\\w-]+) ?([\\w]+=[\\w]+)?"+this.ctag),function(c,d,e){if(!b.pragmas_implemented[d])throw{message:"This implementation of mustache doesn't understand the '"+d+"' pragma"};b.pragmas[d]={};if(e){c=e.split("=");b.pragmas[d][c[0]]=c[1]}return""})},render_partial:function(a,b,c){a=this.trim(a);if(!c||c[a]===undefined)throw{message:"unknown_partial '"+a+"'"};if(typeof b[a]!="object")return this.render(c[a],b,c,true);return this.render(c[a],b[a],c,true)},render_section:function(a,
3 | b,c){if(!this.includes("#",a)&&!this.includes("^",a))return a;var d=this;return a.replace(RegExp(this.otag+"(\\^|\\#)\\s*(.+)\\s*"+this.ctag+"\n*([\\s\\S]+?)"+this.otag+"\\/\\s*\\2\\s*"+this.ctag+"\\s*","mg"),function(e,j,k,h){e=d.find(k,b);if(j=="^")return!e||d.is_array(e)&&e.length===0?d.render(h,b,c,true):"";else if(j=="#")return d.is_array(e)?d.map(e,function(g){return d.render(h,d.create_context(g),c,true)}).join(""):d.is_object(e)?d.render(h,d.create_context(e),c,true):typeof e==="function"?
4 | e.call(b,h,function(g){return d.render(g,b,c,true)}):e?d.render(h,b,c,true):""})},render_tags:function(a,b,c,d){var e=this,j=function(){return RegExp(e.otag+"(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?"+e.ctag+"+","g")},k=j(),h=function(o,m,l){switch(m){case "!":return"";case "=":e.set_delimiters(l);k=j();return"";case ">":return e.render_partial(l,b,c);case "{":return e.find(l,b);default:return e.escape(e.find(l,b))}};a=a.split("\n");for(var g=0;g\\]/g,function(b){switch(b){case "&":return"&";case "\\":return"\\\\";case '"':return'"';case "<":return"<";case ">":return">";default:return b}})},create_context:function(a){if(this.is_object(a))return a;else{var b=".";if(this.pragmas["IMPLICIT-ITERATOR"])b=this.pragmas["IMPLICIT-ITERATOR"].iterator;var c={};c[b]=a;return c}},
7 | is_object:function(a){return a&&typeof a=="object"},is_array:function(a){return Object.prototype.toString.call(a)==="[object Array]"},trim:function(a){return a.replace(/^\s*|\s*$/g,"")},map:function(a,b){if(typeof a.map=="function")return a.map(b);else{for(var c=[],d=a.length,e=0;e=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,
13 | c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};h(a,function(a,b,f){b=c?c.call(d,a,b,f):a;bd?1:0}),"value")};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.zip=function(){for(var a=f.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),
16 | e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return function(){if(--a<1)return b.apply(this,arguments)}};b.keys=F||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)l.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,
20 | b.identity)};b.functions=b.methods=function(a){return b.filter(b.keys(a),function(c){return b.isFunction(a[c])}).sort()};b.extend=function(a){h(f.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){h(f.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,c){if(a===c)return!0;var d=typeof a;if(d!=
21 | typeof c)return!1;if(a==c)return!0;if(!a&&c||a&&!c)return!1;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual)return a.isEqual(c);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return!1;if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return!1;if(a.length&&a.length!==c.length)return!1;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return!1;
22 | for(var f in a)if(!(f in c)||!b.isEqual(a[f],c[f]))return!1;return!0};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(l.call(a,c))return!1;return!0};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=n||function(a){return E.call(a)==="[object Array]"};b.isArguments=function(a){return!(!a||!l.call(a,"callee"))};b.isFunction=function(a){return!(!a||!a.constructor||!a.call||!a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};
23 | b.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===!0||a===!1};b.isDate=function(a){return!(!a||!a.getTimezoneOffset||!a.setUTCFullYear)};b.isRegExp=function(a){return!(!a||!a.test||!a.exec||!(a.ignoreCase||a.ignoreCase===!1))};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){p._=C;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=
24 | 0;e/g,interpolate:/<%=([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||
25 | null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return c?d(c):d};var j=function(a){this._wrapped=a};b.prototype=j.prototype;var r=function(a,c){return c?b(a).chain():a},H=function(a,c){j.prototype[a]=function(){var a=f.call(arguments);D.call(a,this._wrapped);return r(c.apply(b,a),this._chain)}};b.mixin(b);h(["pop","push","reverse","shift","sort",
26 | "splice","unshift"],function(a){var b=i[a];j.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});h(["concat","join","slice"],function(a){var b=i[a];j.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});j.prototype.chain=function(){this._chain=!0;return this};j.prototype.value=function(){return this._wrapped}})();
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | == Welcome to Rails
2 |
3 | Rails is a web-application framework that includes everything needed to create
4 | database-backed web applications according to the Model-View-Control pattern.
5 |
6 | This pattern splits the view (also called the presentation) into "dumb"
7 | templates that are primarily responsible for inserting pre-built data in between
8 | HTML tags. The model contains the "smart" domain objects (such as Account,
9 | Product, Person, Post) that holds all the business logic and knows how to
10 | persist themselves to a database. The controller handles the incoming requests
11 | (such as Save New Account, Update Product, Show Post) by manipulating the model
12 | and directing data to the view.
13 |
14 | In Rails, the model is handled by what's called an object-relational mapping
15 | layer entitled Active Record. This layer allows you to present the data from
16 | database rows as objects and embellish these data objects with business logic
17 | methods. You can read more about Active Record in
18 | link:files/vendor/rails/activerecord/README.html.
19 |
20 | The controller and view are handled by the Action Pack, which handles both
21 | layers by its two parts: Action View and Action Controller. These two layers
22 | are bundled in a single package due to their heavy interdependence. This is
23 | unlike the relationship between the Active Record and Action Pack that is much
24 | more separate. Each of these packages can be used independently outside of
25 | Rails. You can read more about Action Pack in
26 | link:files/vendor/rails/actionpack/README.html.
27 |
28 |
29 | == Getting Started
30 |
31 | 1. At the command prompt, create a new Rails application:
32 | rails new myapp (where myapp is the application name)
33 |
34 | 2. Change directory to myapp and start the web server:
35 | cd myapp; rails server (run with --help for options)
36 |
37 | 3. Go to http://localhost:3000/ and you'll see:
38 | "Welcome aboard: You're riding Ruby on Rails!"
39 |
40 | 4. Follow the guidelines to start developing your application. You can find
41 | the following resources handy:
42 |
43 | * The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
44 | * Ruby on Rails Tutorial Book: http://www.railstutorial.org/
45 |
46 |
47 | == Debugging Rails
48 |
49 | Sometimes your application goes wrong. Fortunately there are a lot of tools that
50 | will help you debug it and get it back on the rails.
51 |
52 | First area to check is the application log files. Have "tail -f" commands
53 | running on the server.log and development.log. Rails will automatically display
54 | debugging and runtime information to these files. Debugging info will also be
55 | shown in the browser on requests from 127.0.0.1.
56 |
57 | You can also log your own messages directly into the log file from your code
58 | using the Ruby logger class from inside your controllers. Example:
59 |
60 | class WeblogController < ActionController::Base
61 | def destroy
62 | @weblog = Weblog.find(params[:id])
63 | @weblog.destroy
64 | logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
65 | end
66 | end
67 |
68 | The result will be a message in your log file along the lines of:
69 |
70 | Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1!
71 |
72 | More information on how to use the logger is at http://www.ruby-doc.org/core/
73 |
74 | Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
75 | several books available online as well:
76 |
77 | * Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe)
78 | * Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
79 |
80 | These two books will bring you up to speed on the Ruby language and also on
81 | programming in general.
82 |
83 |
84 | == Debugger
85 |
86 | Debugger support is available through the debugger command when you start your
87 | Mongrel or WEBrick server with --debugger. This means that you can break out of
88 | execution at any point in the code, investigate and change the model, and then,
89 | resume execution! You need to install ruby-debug to run the server in debugging
90 | mode. With gems, use sudo gem install ruby-debug. Example:
91 |
92 | class WeblogController < ActionController::Base
93 | def index
94 | @posts = Post.find(:all)
95 | debugger
96 | end
97 | end
98 |
99 | So the controller will accept the action, run the first line, then present you
100 | with a IRB prompt in the server window. Here you can do things like:
101 |
102 | >> @posts.inspect
103 | => "[#nil, "body"=>nil, "id"=>"1"}>,
105 | #"Rails", "body"=>"Only ten..", "id"=>"2"}>]"
107 | >> @posts.first.title = "hello from a debugger"
108 | => "hello from a debugger"
109 |
110 | ...and even better, you can examine how your runtime objects actually work:
111 |
112 | >> f = @posts.first
113 | => #nil, "body"=>nil, "id"=>"1"}>
114 | >> f.
115 | Display all 152 possibilities? (y or n)
116 |
117 | Finally, when you're ready to resume execution, you can enter "cont".
118 |
119 |
120 | == Console
121 |
122 | The console is a Ruby shell, which allows you to interact with your
123 | application's domain model. Here you'll have all parts of the application
124 | configured, just like it is when the application is running. You can inspect
125 | domain models, change values, and save to the database. Starting the script
126 | without arguments will launch it in the development environment.
127 |
128 | To start the console, run rails console from the application
129 | directory.
130 |
131 | Options:
132 |
133 | * Passing the -s, --sandbox argument will rollback any modifications
134 | made to the database.
135 | * Passing an environment name as an argument will load the corresponding
136 | environment. Example: rails console production.
137 |
138 | To reload your controllers and models after launching the console run
139 | reload!
140 |
141 | More information about irb can be found at:
142 | link:http://www.rubycentral.com/pickaxe/irb.html
143 |
144 |
145 | == dbconsole
146 |
147 | You can go to the command line of your database directly through rails
148 | dbconsole. You would be connected to the database with the credentials
149 | defined in database.yml. Starting the script without arguments will connect you
150 | to the development database. Passing an argument will connect you to a different
151 | database, like rails dbconsole production. Currently works for MySQL,
152 | PostgreSQL and SQLite 3.
153 |
154 | == Description of Contents
155 |
156 | The default directory structure of a generated Ruby on Rails application:
157 |
158 | |-- app
159 | | |-- controllers
160 | | |-- helpers
161 | | |-- mailers
162 | | |-- models
163 | | `-- views
164 | | `-- layouts
165 | |-- config
166 | | |-- environments
167 | | |-- initializers
168 | | `-- locales
169 | |-- db
170 | |-- doc
171 | |-- lib
172 | | `-- tasks
173 | |-- log
174 | |-- public
175 | | |-- images
176 | | |-- javascripts
177 | | `-- stylesheets
178 | |-- script
179 | |-- test
180 | | |-- fixtures
181 | | |-- functional
182 | | |-- integration
183 | | |-- performance
184 | | `-- unit
185 | |-- tmp
186 | | |-- cache
187 | | |-- pids
188 | | |-- sessions
189 | | `-- sockets
190 | `-- vendor
191 | `-- plugins
192 |
193 | app
194 | Holds all the code that's specific to this particular application.
195 |
196 | app/controllers
197 | Holds controllers that should be named like weblogs_controller.rb for
198 | automated URL mapping. All controllers should descend from
199 | ApplicationController which itself descends from ActionController::Base.
200 |
201 | app/models
202 | Holds models that should be named like post.rb. Models descend from
203 | ActiveRecord::Base by default.
204 |
205 | app/views
206 | Holds the template files for the view that should be named like
207 | weblogs/index.html.erb for the WeblogsController#index action. All views use
208 | eRuby syntax by default.
209 |
210 | app/views/layouts
211 | Holds the template files for layouts to be used with views. This models the
212 | common header/footer method of wrapping views. In your views, define a layout
213 | using the layout :default and create a file named default.html.erb.
214 | Inside default.html.erb, call <% yield %> to render the view using this
215 | layout.
216 |
217 | app/helpers
218 | Holds view helpers that should be named like weblogs_helper.rb. These are
219 | generated for you automatically when using generators for controllers.
220 | Helpers can be used to wrap functionality for your views into methods.
221 |
222 | config
223 | Configuration files for the Rails environment, the routing map, the database,
224 | and other dependencies.
225 |
226 | db
227 | Contains the database schema in schema.rb. db/migrate contains all the
228 | sequence of Migrations for your schema.
229 |
230 | doc
231 | This directory is where your application documentation will be stored when
232 | generated using rake doc:app
233 |
234 | lib
235 | Application specific libraries. Basically, any kind of custom code that
236 | doesn't belong under controllers, models, or helpers. This directory is in
237 | the load path.
238 |
239 | public
240 | The directory available for the web server. Contains subdirectories for
241 | images, stylesheets, and javascripts. Also contains the dispatchers and the
242 | default HTML files. This should be set as the DOCUMENT_ROOT of your web
243 | server.
244 |
245 | script
246 | Helper scripts for automation and generation.
247 |
248 | test
249 | Unit and functional tests along with fixtures. When using the rails generate
250 | command, template test files will be generated for you and placed in this
251 | directory.
252 |
253 | vendor
254 | External libraries that the application depends on. Also includes the plugins
255 | subdirectory. If the app has frozen rails, those gems also go here, under
256 | vendor/rails/. This directory is in the load path.
257 |
--------------------------------------------------------------------------------
/public/javascripts/backbone.min.js:
--------------------------------------------------------------------------------
1 | // Backbone.js 0.3.3
2 | // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Backbone may be freely distributed under the MIT license.
4 | // For all details and documentation:
5 | // http://documentcloud.github.com/backbone
6 | (function(){var e;e=typeof exports!=="undefined"?exports:this.Backbone={};e.VERSION="0.3.3";var f=this._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var h=this.jQuery||this.Zepto;e.emulateHTTP=false;e.emulateJSON=false;e.Events={bind:function(a,b){this._callbacks||(this._callbacks={});(this._callbacks[a]||(this._callbacks[a]=[])).push(b);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d=0,g=c.length;d/g,">").replace(/"/g,
9 | """)},set:function(a,b){b||(b={});if(!a)return this;if(a.attributes)a=a.attributes;var c=this.attributes,d=this._escapedAttributes;if(!b.silent&&this.validate&&!this._performValidation(a,b))return false;if("id"in a)this.id=a.id;for(var g in a){var i=a[g];if(!f.isEqual(c[g],i)){c[g]=i;delete d[g];if(!b.silent){this._changed=true;this.trigger("change:"+g,this,i,b)}}}!b.silent&&this._changed&&this.change(b);return this},unset:function(a,b){b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&&
10 | !this._performValidation(c,b))return false;delete this.attributes[a];delete this._escapedAttributes[a];if(!b.silent){this._changed=true;this.trigger("change:"+a,this,void 0,b);this.change(b)}return this},clear:function(a){a||(a={});var b=this.attributes,c={};for(attr in b)c[attr]=void 0;if(!a.silent&&this.validate&&!this._performValidation(c,a))return false;this.attributes={};this._escapedAttributes={};if(!a.silent){this._changed=true;for(attr in b)this.trigger("change:"+attr,this,void 0,a);this.change(a)}return this},
11 | fetch:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("read",this,function(d){if(!b.set(b.parse(d),a))return false;a.success&&a.success(b,d)},c);return this},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return false;var c=this,d=j(b.error,c,b),g=this.isNew()?"create":"update";(this.sync||e.sync)(g,this,function(i){if(!c.set(c.parse(i),b))return false;b.success&&b.success(c,i)},d);return this},destroy:function(a){a||(a={});var b=this,c=j(a.error,b,a);(this.sync||e.sync)("delete",
12 | this,function(d){b.collection&&b.collection.remove(b);a.success&&a.success(b,d)},c);return this},url:function(){var a=k(this.collection);if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+this.id},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return!this.id},change:function(a){this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);this._changed=false},hasChanged:function(a){if(a)return this._previousAttributes[a]!=
13 | this.attributes[a];return this._changed},changedAttributes:function(a){a||(a=this.attributes);var b=this._previousAttributes,c=false,d;for(d in a)if(!f.isEqual(b[d],a[d])){c=c||{};c[d]=a[d]}return c},previous:function(a){if(!a||!this._previousAttributes)return null;return this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},_performValidation:function(a,b){var c=this.validate(a);if(c){b.error?b.error(this,c):this.trigger("error",this,c,b);return false}return true}});
14 | e.Collection=function(a,b){b||(b={});if(b.comparator){this.comparator=b.comparator;delete b.comparator}this._boundOnModelEvent=f.bind(this._onModelEvent,this);this._reset();a&&this.refresh(a,{silent:true});this.initialize(a,b)};f.extend(e.Collection.prototype,e.Events,{model:e.Model,initialize:function(){},toJSON:function(){return this.map(function(a){return a.toJSON()})},add:function(a,b){if(f.isArray(a))for(var c=0,d=a.length;c').hide().appendTo("body")[0].contentWindow;
22 | "onhashchange"in window&&!a?h(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);return this.loadUrl()},route:function(a,b){this.handlers.push({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();if(a==this.fragment&&this.iframe)a=this.getFragment(this.iframe.location);if(a==this.fragment||a==decodeURIComponent(this.fragment))return false;if(this.iframe)window.location.hash=this.iframe.location.hash=a;this.loadUrl()},loadUrl:function(){var a=this.fragment=
23 | this.getFragment();return f.any(this.handlers,function(b){if(b.route.test(a)){b.callback(a);return true}})},saveLocation:function(a){a=(a||"").replace(l,"");if(this.fragment!=a){window.location.hash=this.fragment=a;if(this.iframe&&a!=this.getFragment(this.iframe.location)){this.iframe.document.open().close();this.iframe.location.hash=a}}}});e.View=function(a){this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize(a)};var q=/^(\w+)\s*(.*)$/;f.extend(e.View.prototype,e.Events,
24 | {tagName:"div",$:function(a){return h(a,this.el)},initialize:function(){},render:function(){return this},remove:function(){h(this.el).remove();return this},make:function(a,b,c){a=document.createElement(a);b&&h(a).attr(b);c&&h(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events)){h(this.el).unbind();for(var b in a){var c=a[b],d=b.match(q),g=d[1];d=d[2];c=f.bind(this[c],this);d===""?h(this.el).bind(g,c):h(this.el).delegate(d,g,c)}}},_configure:function(a){if(this.options)a=f.extend({},
25 | this.options,a);if(a.model)this.model=a.model;if(a.collection)this.collection=a.collection;if(a.el)this.el=a.el;if(a.id)this.id=a.id;if(a.className)this.className=a.className;if(a.tagName)this.tagName=a.tagName;this.options=a},_ensureElement:function(){if(!this.el){var a={};if(this.id)a.id=this.id;if(this.className)a["class"]=this.className;this.el=this.make(this.tagName,a)}}});var m=function(a,b){var c=r(this,a,b);c.extend=m;return c};e.Model.extend=e.Collection.extend=e.Controller.extend=e.View.extend=
26 | m;var s={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};e.sync=function(a,b,c,d){var g=s[a];a=a==="create"||a==="update"?JSON.stringify(b.toJSON()):null;b={url:k(b),type:g,contentType:"application/json",data:a,dataType:"json",processData:false,success:c,error:d};if(e.emulateJSON){b.contentType="application/x-www-form-urlencoded";b.processData=true;b.data=a?{model:a}:{}}if(e.emulateHTTP)if(g==="PUT"||g==="DELETE"){if(e.emulateJSON)b.data._method=g;b.type="POST";b.beforeSend=function(i){i.setRequestHeader("X-HTTP-Method-Override",
27 | g)}}h.ajax(b)};var n=function(){},r=function(a,b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){return a.apply(this,arguments)};n.prototype=a.prototype;d.prototype=new n;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},k=function(a){if(!(a&&a.url))throw Error("A 'url' property or function must be specified");return f.isFunction(a.url)?a.url():a.url},j=function(a,b,c){return function(d){a?a(b,d):b.trigger("error",b,d,c)}}})();
--------------------------------------------------------------------------------
/public/javascripts/icanhaz.js:
--------------------------------------------------------------------------------
1 | /*!
2 | ICanHaz.js version 0.9 -- by @HenrikJoreteg
3 | More info at: http://icanhazjs.com
4 | */
5 | (function ($) {
6 | /*!
7 | mustache.js -- Logic-less templates in JavaScript
8 |
9 | by @janl (MIT Licensed, https://github.com/janl/mustache.js/blob/master/LICENSE).
10 |
11 | See http://mustache.github.com/ for more info.
12 | */
13 |
14 | var Mustache = function() {
15 | var Renderer = function() {};
16 |
17 | Renderer.prototype = {
18 | otag: "{{",
19 | ctag: "}}",
20 | pragmas: {},
21 | buffer: [],
22 | pragmas_implemented: {
23 | "IMPLICIT-ITERATOR": true
24 | },
25 | context: {},
26 |
27 | render: function(template, context, partials, in_recursion) {
28 | // reset buffer & set context
29 | if(!in_recursion) {
30 | this.context = context;
31 | this.buffer = []; // TODO: make this non-lazy
32 | }
33 |
34 | // fail fast
35 | if(!this.includes("", template)) {
36 | if(in_recursion) {
37 | return template;
38 | } else {
39 | this.send(template);
40 | return;
41 | }
42 | }
43 |
44 | template = this.render_pragmas(template);
45 | var html = this.render_section(template, context, partials);
46 | if(in_recursion) {
47 | return this.render_tags(html, context, partials, in_recursion);
48 | }
49 |
50 | this.render_tags(html, context, partials, in_recursion);
51 | },
52 |
53 | /*
54 | Sends parsed lines
55 | */
56 | send: function(line) {
57 | if(line != "") {
58 | this.buffer.push(line);
59 | }
60 | },
61 |
62 | /*
63 | Looks for %PRAGMAS
64 | */
65 | render_pragmas: function(template) {
66 | // no pragmas
67 | if(!this.includes("%", template)) {
68 | return template;
69 | }
70 |
71 | var that = this;
72 | var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
73 | this.ctag);
74 | return template.replace(regex, function(match, pragma, options) {
75 | if(!that.pragmas_implemented[pragma]) {
76 | throw({message:
77 | "This implementation of mustache doesn't understand the '" +
78 | pragma + "' pragma"});
79 | }
80 | that.pragmas[pragma] = {};
81 | if(options) {
82 | var opts = options.split("=");
83 | that.pragmas[pragma][opts[0]] = opts[1];
84 | }
85 | return "";
86 | // ignore unknown pragmas silently
87 | });
88 | },
89 |
90 | /*
91 | Tries to find a partial in the curent scope and render it
92 | */
93 | render_partial: function(name, context, partials) {
94 | name = this.trim(name);
95 | if(!partials || partials[name] === undefined) {
96 | throw({message: "unknown_partial '" + name + "'"});
97 | }
98 | if(typeof(context[name]) != "object") {
99 | return this.render(partials[name], context, partials, true);
100 | }
101 | return this.render(partials[name], context[name], partials, true);
102 | },
103 |
104 | /*
105 | Renders inverted (^) and normal (#) sections
106 | */
107 | render_section: function(template, context, partials) {
108 | if(!this.includes("#", template) && !this.includes("^", template)) {
109 | return template;
110 | }
111 |
112 | var that = this;
113 | // CSW - Added "+?" so it finds the tighest bound, not the widest
114 | var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
115 | "\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
116 | "\\s*", "mg");
117 |
118 | // for each {{#foo}}{{/foo}} section do...
119 | return template.replace(regex, function(match, type, name, content) {
120 | var value = that.find(name, context);
121 | if(type == "^") { // inverted section
122 | if(!value || that.is_array(value) && value.length === 0) {
123 | // false or empty list, render it
124 | return that.render(content, context, partials, true);
125 | } else {
126 | return "";
127 | }
128 | } else if(type == "#") { // normal section
129 | if(that.is_array(value)) { // Enumerable, Let's loop!
130 | return that.map(value, function(row) {
131 | return that.render(content, that.create_context(row),
132 | partials, true);
133 | }).join("");
134 | } else if(that.is_object(value)) { // Object, Use it as subcontext!
135 | return that.render(content, that.create_context(value),
136 | partials, true);
137 | } else if(typeof value === "function") {
138 | // higher order section
139 | return value.call(context, content, function(text) {
140 | return that.render(text, context, partials, true);
141 | });
142 | } else if(value) { // boolean section
143 | return that.render(content, context, partials, true);
144 | } else {
145 | return "";
146 | }
147 | }
148 | });
149 | },
150 |
151 | /*
152 | Replace {{foo}} and friends with values from our view
153 | */
154 | render_tags: function(template, context, partials, in_recursion) {
155 | // tit for tat
156 | var that = this;
157 |
158 | var new_regex = function() {
159 | return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
160 | that.ctag + "+", "g");
161 | };
162 |
163 | var regex = new_regex();
164 | var tag_replace_callback = function(match, operator, name) {
165 | switch(operator) {
166 | case "!": // ignore comments
167 | return "";
168 | case "=": // set new delimiters, rebuild the replace regexp
169 | that.set_delimiters(name);
170 | regex = new_regex();
171 | return "";
172 | case ">": // render partial
173 | return that.render_partial(name, context, partials);
174 | case "{": // the triple mustache is unescaped
175 | return that.find(name, context);
176 | default: // escape the value
177 | return that.escape(that.find(name, context));
178 | }
179 | };
180 | var lines = template.split("\n");
181 | for(var i = 0; i < lines.length; i++) {
182 | lines[i] = lines[i].replace(regex, tag_replace_callback, this);
183 | if(!in_recursion) {
184 | this.send(lines[i]);
185 | }
186 | }
187 |
188 | if(in_recursion) {
189 | return lines.join("\n");
190 | }
191 | },
192 |
193 | set_delimiters: function(delimiters) {
194 | var dels = delimiters.split(" ");
195 | this.otag = this.escape_regex(dels[0]);
196 | this.ctag = this.escape_regex(dels[1]);
197 | },
198 |
199 | escape_regex: function(text) {
200 | // thank you Simon Willison
201 | if(!arguments.callee.sRE) {
202 | var specials = [
203 | '/', '.', '*', '+', '?', '|',
204 | '(', ')', '[', ']', '{', '}', '\\'
205 | ];
206 | arguments.callee.sRE = new RegExp(
207 | '(\\' + specials.join('|\\') + ')', 'g'
208 | );
209 | }
210 | return text.replace(arguments.callee.sRE, '\\$1');
211 | },
212 |
213 | /*
214 | find `name` in current `context`. That is find me a value
215 | from the view object
216 | */
217 | find: function(name, context) {
218 | name = this.trim(name);
219 |
220 | // Checks whether a value is thruthy or false or 0
221 | function is_kinda_truthy(bool) {
222 | return bool === false || bool === 0 || bool;
223 | }
224 |
225 | var value;
226 | if(is_kinda_truthy(context[name])) {
227 | value = context[name];
228 | } else if(is_kinda_truthy(this.context[name])) {
229 | value = this.context[name];
230 | }
231 |
232 | if(typeof value === "function") {
233 | return value.apply(context);
234 | }
235 | if(value !== undefined) {
236 | return value;
237 | }
238 | // silently ignore unkown variables
239 | return "";
240 | },
241 |
242 | // Utility methods
243 |
244 | /* includes tag */
245 | includes: function(needle, haystack) {
246 | return haystack.indexOf(this.otag + needle) != -1;
247 | },
248 |
249 | /*
250 | Does away with nasty characters
251 | */
252 | escape: function(s) {
253 | s = String(s === null ? "" : s);
254 | return s.replace(/&(?!\w+;)|["<>\\]/g, function(s) {
255 | switch(s) {
256 | case "&": return "&";
257 | case "\\": return "\\\\";
258 | case '"': return '\"';
259 | case "<": return "<";
260 | case ">": return ">";
261 | default: return s;
262 | }
263 | });
264 | },
265 |
266 | // by @langalex, support for arrays of strings
267 | create_context: function(_context) {
268 | if(this.is_object(_context)) {
269 | return _context;
270 | } else {
271 | var iterator = ".";
272 | if(this.pragmas["IMPLICIT-ITERATOR"]) {
273 | iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
274 | }
275 | var ctx = {};
276 | ctx[iterator] = _context;
277 | return ctx;
278 | }
279 | },
280 |
281 | is_object: function(a) {
282 | return a && typeof a == "object";
283 | },
284 |
285 | is_array: function(a) {
286 | return Object.prototype.toString.call(a) === '[object Array]';
287 | },
288 |
289 | /*
290 | Gets rid of leading and trailing whitespace
291 | */
292 | trim: function(s) {
293 | return s.replace(/^\s*|\s*$/g, "");
294 | },
295 |
296 | /*
297 | Why, why, why? Because IE. Cry, cry cry.
298 | */
299 | map: function(array, fn) {
300 | if (typeof array.map == "function") {
301 | return array.map(fn);
302 | } else {
303 | var r = [];
304 | var l = array.length;
305 | for(var i = 0; i < l; i++) {
306 | r.push(fn(array[i]));
307 | }
308 | return r;
309 | }
310 | }
311 | };
312 |
313 | return({
314 | name: "mustache.js",
315 | version: "0.3.0",
316 |
317 | /*
318 | Turns a template and view into HTML
319 | */
320 | to_html: function(template, view, partials, send_fun) {
321 | var renderer = new Renderer();
322 | if(send_fun) {
323 | renderer.send = send_fun;
324 | }
325 | renderer.render(template, view, partials);
326 | if(!send_fun) {
327 | return renderer.buffer.join("\n");
328 | }
329 | }
330 | });
331 | }();/*!
332 | ICanHaz.js -- by @HenrikJoreteg
333 | */
334 | /*global jQuery */
335 | function ICanHaz() {
336 | var self = this;
337 | self.VERSION = "0.9";
338 | self.templates = {};
339 | self.partials = {};
340 |
341 | // public function for adding templates
342 | // We're enforcing uniqueness to avoid accidental template overwrites.
343 | // If you want a different template, it should have a different name.
344 | self.addTemplate = function (name, templateString) {
345 | if (self[name]) throw "Invalid name: " + name + ".";
346 | if (self.templates[name]) throw "Template \" + name + \" exists";
347 |
348 | self.templates[name] = templateString;
349 | self[name] = function (data, raw) {
350 | data = data || {};
351 | var result = Mustache.to_html(self.templates[name], data, self.partials);
352 | return raw ? result : $(result);
353 | };
354 | };
355 |
356 | // public function for adding partials
357 | self.addPartial = function (name, templateString) {
358 | if (self.partials[name]) {
359 | throw "Partial \" + name + \" exists";
360 | } else {
361 | self.partials[name] = templateString;
362 | }
363 | };
364 |
365 | // grabs templates from the DOM and caches them.
366 | // Loop through and add templates.
367 | // Whitespace at beginning and end of all templates inside