working stack ?

This commit is contained in:
dinedine 2010-04-09 11:23:41 +02:00
parent a9fb66f9c1
commit cd67a29b88
29 changed files with 612 additions and 92 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
db/*.sqlite3
log/*.log
tmp/**/*
.DS_Store

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "vendor/plugins/remarkable_mongo"]
path = vendor/plugins/remarkable_mongo
url = git@github.com:did/remarkable_mongo.git

47
Gemfile
View File

@ -1,42 +1,31 @@
# Edit this Gemfile to bundle your application"s dependencies.
source "http://gemcutter.org"
source "http://gems.github.com"
gem "rails", "3.0.0.beta"
gem "rails", "3.0.0.beta2"
gem "liquid"
gem "bson_ext"
gem "mongo_ext"
gem "mongo_mapper"
gem "mongoid", ">= 2.0.0.beta"
gem "warden"
gem "devise", ">= 1.1.rc0"
# Using mongrel instead of webrick (default server)
gem "mongrel"
gem "cgi_multipart_eof_fix"
gem "fastthread"
gem "mongrel_experimental"
# Test environment
group :test do
gem "rspec"
gem "rspec-rails"
gem "factory_girl", :git => "git://github.com/szimek/factory_girl.git", :branch => "rails3"
gem "shoulda", :require => nil
gem "remarkable_rails"
gem "webrat"
gem "cucumber"
# Development environment
group :development do
# Using mongrel instead of webrick (default server)
gem "mongrel"
gem "cgi_multipart_eof_fix"
gem "fastthread"
gem "mongrel_experimental"
end
## Bundle edge rails:
# gem "rails", :git => "git://github.com/rails/rails.git"
gem 'rspec', '>= 2.0.0.beta.4'
gem 'rspec-rails', '>= 2.0.0.beta.4'
gem 'factory_girl', :git => 'git://github.com/thoughtbot/factory_girl.git', :branch => 'rails3'
# ActiveRecord requires a database adapter. By default,
# Rails has selected sqlite3.
# gem "sqlite3-ruby", :require => "sqlite3"
## Bundle the gems you use:
# gem "bj"
# gem "hpricot", "0.6"
# gem "sqlite3-ruby", :require => "sqlite3"
# gem "aws-s3", :require => "aws/s3"
## Bundle gems used only in certain environments:
# gem "rspec", :group => :test
# gem "shoulda", :git => "git://github.com/sinefunc/shoulda.git", :branch => "rails3"
# gem "shoulda", :git => "git://github.com/bmaddy/shoulda.git", :branch => "rails3", :require => nil

17
app/models/account.rb Normal file
View File

@ -0,0 +1,17 @@
class Account
# include MongoMapper::Document
## Attributes
# key :name
# key :locale
# timestamps!
# Include default devise modules. Others available are:
# :http_authenticatable, :token_authenticatable, :lockable, :timeoutable and :activatable
# devise :registerable, :authenticatable, :confirmable, :recoverable,
# :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
# attr_accessible :email, :password, :password_confirmation
end

32
app/models/site.rb Normal file
View File

@ -0,0 +1,32 @@
class Site
include Mongoid::Document
include Mongoid::Timestamps
## fields ##
field :name
field :domains, :type => Array, :default => []
## validations ##
validates_presence_of :name
validates_length_of :domains, :minimum => 1
# validates_each :domains, :logic => :domains_are_unique_and_valid
## behaviours ##
# timestamps!
## methods ##
def subdomain=(value)
return if value.blank?
(self.domains << "#{value}.#{Locomotive::Configuration.default_domain_name}").uniq!
end
protected
def domains_are_unique_and_valid
# self.domains.each do |domain|
# self.errors.add(:domains, t())
# end
end
end

View File

@ -1,6 +1,10 @@
require File.expand_path('../boot', __FILE__)
require 'rails/all'
# require 'rails/all'
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
# Auto-require default libraries and those for the current Rails environment.
Bundler.require :default, Rails.env
@ -37,6 +41,6 @@ module Locomotive
# end
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters << :password
config.filter_parameters << :password
end
end

View File

@ -1,22 +1,17 @@
# SQLite version 3.x
# gem install sqlite3-ruby (not necessary on OS X Leopard)
development:
adapter: sqlite3
database: db/development.sqlite3
pool: 5
timeout: 5000
defaults: &defaults
host: localhost
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
development:
<<: *defaults
database: locomotive_dev
test:
adapter: sqlite3
database: db/test.sqlite3
pool: 5
timeout: 5000
<<: *defaults
database: locomotive_test
production:
adapter: sqlite3
database: db/production.sqlite3
pool: 5
timeout: 5000
<<: *defaults
host: db.mongohq.com
username: user
password: pass
database: fanboy

View File

@ -16,4 +16,6 @@ Locomotive::Application.configure do
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = false
# config.action_mailer.default_url_options = { :host => 'localhost:3000' }
end

View File

@ -1,7 +1 @@
# Be sure to restart your server when you modify this file.
# Your secret key for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
ActionController::Base.cookie_verifier_secret = 'e3ec925c3e73a2d3d84b14fbd82691ed0757426e87a953be2b80b6f221a0b4aa6ad660c13aa8944cf4739fc887f3403615bb445916e9ff7ce490ea75eb8fefab'
Rails.application.config.cookie_secret = '968a457262807c64e3ed5609882e17a774b917f5bcf2d308bd37eac4ba4d416d5692e6b13d77523fddb94c1dd603f160db8492b86b5e0203240bf339fe2aeae4'

View File

@ -0,0 +1,117 @@
# Use this hook to configure devise mailer, warden hooks and so forth. The first
# four configuration values can also be set straight in your models.
Devise.setup do |config|
# Configure the e-mail address which will be shown in DeviseMailer.
config.mailer_sender = "support@locomotiveapp.org"
# ==> Configuration for any authentication mechanism
# Configure which keys are used when authenticating an user. By default is
# just :email. You can configure it to use [:username, :subdomain], so for
# authenticating an user, both parameters are required. Remember that those
# parameters are used only when authenticating and not when retrieving from
# session. If you need permissions, you should implement that in a before filter.
# config.authentication_keys = [ :email ]
# Tell if authentication through request.params is enabled. True by default.
# config.params_authenticatable = true
# Tell if authentication through HTTP Basic Auth is enabled. True by default.
# config.http_authenticatable = true
# The realm used in Http Basic Authentication
# config.http_authentication_realm = "Application"
# ==> Configuration for :database_authenticatable
# Invoke `rake secret` and use the printed value to setup a pepper to generate
# the encrypted password. By default no pepper is used.
# config.pepper = "rake secret output"
# Configure how many times you want the password is reencrypted. Default is 10.
# config.stretches = 10
# Define which will be the encryption algorithm. Supported algorithms are :sha1
# (default), :sha512 and :bcrypt. Devise also supports encryptors from others
# authentication tools as :clearance_sha1, :authlogic_sha512 (then you should set
# stretches above to 20 for default behavior) and :restful_authentication_sha1
# (then you should set stretches to 10, and copy REST_AUTH_SITE_KEY to pepper)
# config.encryptor = :sha1
# ==> Configuration for :confirmable
# The time you want give to your user to confirm his account. During this time
# he will be able to access your application without confirming. Default is nil.
# config.confirm_within = 2.days
# ==> Configuration for :rememberable
# The time the user will be remembered without asking for credentials again.
# config.remember_for = 2.weeks
# ==> Configuration for :validatable
# Range for password length
# config.password_length = 6..20
# Regex to use to validate the email address
# config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again.
# config.timeout_in = 10.minutes
# ==> Configuration for :lockable
# Defines which strategy will be used to lock an account.
# :failed_attempts = Locks an account after a number of failed attempts to sign in.
# :none = No lock strategy. You should handle locking by yourself.
# config.lock_strategy = :failed_attempts
# Defines which strategy will be used to unlock an account.
# :email = Sends an unlock link to the user email
# :time = Reanables login after a certain ammount of time (see :unlock_in below)
# :both = Enables both strategies
# :none = No unlock strategy. You should handle unlocking by yourself.
# config.unlock_strategy = :both
# Number of authentication tries before locking an account if lock_strategy
# is failed attempts.
# config.maximum_attempts = 20
# Time interval to unlock the account if :time is enabled as unlock_strategy.
# config.unlock_in = 1.hour
# ==> Configuration for :token_authenticatable
# Defines name of the authentication token params key
# config.token_authentication_key = :auth_token
# ==> General configuration
# Load and configure the ORM. Supports :active_record (default), :mongoid
# (requires mongo_ext installed) and :data_mapper (experimental).
# require 'devise/orm/active_record'
require 'devise/orm/mongoid'
# Turn scoped views on. Before rendering "sessions/new", it will first check for
# "sessions/users/new". It's turned off by default because it's slower if you
# are using only default views.
# config.scoped_views = true
# By default, devise detects the role accessed based on the url. So whenever
# accessing "/users/sign_in", it knows you are accessing an User. This makes
# routes as "/sign_in" not possible, unless you tell Devise to use the default
# scope, setting true below.
# config.use_default_scope = true
# Configure the default scope used by Devise. By default it's the first devise
# role declared in your routes.
# config.default_scope = :user
# If you want to use other strategies, that are not (yet) supported by Devise,
# you can configure them inside the config.warden block. The example below
# allows you to setup OAuth, using http://github.com/roman/warden_oauth
#
# config.warden do |manager|
# manager.oauth(:twitter) do |twitter|
# twitter.consumer_secret = <YOUR CONSUMER SECRET>
# twitter.consumer_key = <YOUR CONSUMER KEY>
# twitter.options :site => 'http://twitter.com'
# end
# manager.default_strategies(:scope => :user).unshift :twitter_oauth
# end
end

View File

@ -0,0 +1,3 @@
Locomotive::Configuration.setup do |config|
config.default_domain_name = 'example.com'
end

View File

@ -0,0 +1,13 @@
File.open(File.join(Rails.root, 'config/database.yml'), 'r') do |f|
@settings = YAML.load(f)[Rails.env]
end
Mongoid.configure do |config|
name = @settings["database"]
host = @settings["host"]
config.master = Mongo::Connection.new.db(name)
# config.slaves = [
# Mongo::Connection.new(host, @settings["slave_one"]["port"], :slave_ok => true).db(name),
# Mongo::Connection.new(host, @settings["slave_two"]["port"], :slave_ok => true).db(name)
# ]
end

View File

@ -0,0 +1,6 @@
Locomotive::Application.configure do
config.generators do |g|
g.integration_tool :rspec
g.test_framework :rspec
end
end

View File

@ -1,15 +1,3 @@
# Be sure to restart your server when you modify this file.
# Your secret key for verifying cookie session data integrity.
# If you change this key, all old sessions will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
ActionController::Base.session = {
:key => '_locomotive_session',
:secret => 'f2049860ac1a8b742808d738ac8a15db5d4be22526f4e497037973f19f59f3b46ae5c97df01cac6637821a9f4aedf9436ceba10e126a4eb278461a03828bf06f'
Rails.application.config.session_store :cookie_store, {
:key => '_locomotive_session',
}
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rake db:sessions:create")
# ActionController::Base.session_store = :active_record_store

View File

@ -0,0 +1,36 @@
en:
errors:
messages:
not_found: "not found"
already_confirmed: "was already confirmed"
not_locked: "was not locked"
devise:
failure:
unauthenticated: 'You need to sign in or sign up before continuing.'
unconfirmed: 'You have to confirm your account before continuing.'
locked: 'Your account is locked.'
invalid: 'Invalid email or password.'
invalid_token: 'Invalid authentication token.'
timeout: 'Your session expired, please sign in again to continue.'
inactive: 'Your account was not activated yet.'
sessions:
signed_in: 'Signed in successfully.'
signed_out: 'Signed out successfully.'
passwords:
send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
updated: 'Your password was changed successfully. You are now signed in.'
confirmations:
send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
confirmed: 'Your account was successfully confirmed. You are now signed in.'
registrations:
signed_up: 'You have signed up successfully.'
updated: 'You updated your account successfully.'
destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
unlocks:
send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
unlocked: 'Your account was successfully unlocked. You are now signed in.'
mailer:
confirmation_instructions: 'Confirmation instructions'
reset_password_instructions: 'Reset password instructions'
unlock_instructions: 'Unlock Instructions'

View File

@ -1,4 +1,6 @@
Locomotive::Application.routes.draw do |map|
# de#vise_for :accounts
# The priority is based upon order of creation:
# first created -> highest priority.

View File

@ -0,0 +1,23 @@
# class DeviseCreateAccounts < ActiveRecord::Migration
# def self.up
# create_table(:accounts) do |t|
# t.authenticatable :encryptor => :sha1, :null => false
# t.confirmable
# t.recoverable
# t.rememberable
# t.trackable
# # t.lockable
#
# t.timestamps
# end
#
# add_index :accounts, :email, :unique => true
# add_index :accounts, :confirmation_token, :unique => true
# add_index :accounts, :reset_password_token, :unique => true
# # add_index :accounts, :unlock_token, :unique => true
# end
#
# def self.down
# drop_table :accounts
# end
# end

View File

@ -0,0 +1,49 @@
module Devise
module Orm
module MongoMapper
module Hook
def devise_modules_hook!
extend Schema
include Compatibility
yield
return unless Devise.apply_schema
devise_modules.each { |m| send(m) if respond_to?(m, true) }
end
end
module Schema
include Devise::Schema
# Tell how to apply schema methods. This automatically converts DateTime
# to Time, since MongoMapper does not recognize the former.
def apply_schema(name, type, options={})
type = Time if type == DateTime
key name, type, options
end
end
module Compatibility
extend ActiveSupport::Concern
module ClassMethods
def find(*args)
case args.first
when :first, :all
send(args.shift, *args)
else
super
end
end
end
end
end
end
end
[MongoMapper::Document, MongoMapper::EmbeddedDocument].each do |mod|
mod::ClassMethods.class_eval do
include Devise::Models
include Devise::Orm::MongoMapper::Hook
end
end

View File

@ -0,0 +1,99 @@
# require 'active_support'
# Custom configuration settings
# code inspired by http://slateinfo.blogs.wvu.edu/
#
# Example:
# Locomotive::Configuration.setup do |config|
# config.title = "Hello world !!!"
#
# config.admin do |admin|
# admin.per_page 10
# end
# end
#
# Locomotive::Configuration.admin.per_page # => "10"
#
# # some alternate ways to access the settings
# Locomotive::Configuration.config[:admin][:per_page] # => "10"
module Locomotive
class Configuration
DEFAULT_SETTINGS = {
:default_domain_name => 'localhost'
}
cattr_accessor :settings
# creates a new configuration object if
# necessary
def self.settings # !> redefine settings
if @@settings.nil?
@@settings = self.get_from_hash(DEFAULT_SETTINGS)
else
@@settings
end
end
def self.setup
block_given? ? yield(self.settings) : self.settings
end
# reset settings
def self.reset
@@settings = nil
end
# returns the current configuration
# by passing a block you can easily edit the
# configuration values
def self.config
block_given? ? yield(self.settings) : self.settings
end
def self.method_missing(name, *args, &block)
self.config.send(name, *args, &block)
end
protected
# converts a hash map into a ConfigurationHash
def self.get_from_hash(hash)
config = ConfigurationHash.new
hash.each_pair do |key, value|
config[key] = value.is_a?(Hash) ? self.get_from_hash(value) : value
end
config
end
end
# specialized hash for storing configuration settings
class ConfigurationHash < Hash
# ensure that default entries always produce
# instances of the ConfigurationHash class
def default(key=nil)
include?(key) ? self[key] : self[key] = self.class.new
end
# retrieves the specified key and yields it
# if a block is provided
def [](key, &block)
block_given? ? yield(super(key)) : super(key)
end
# provides member-based access to keys
# i.e. params.id === params[:id]
# note: all keys are converted to symbols
def method_missing(name, *args, &block)
if name.to_s.ends_with? '='
send :[]=, name.to_s.chomp('=').to_sym, *args
else
send(:[], name.to_sym, &block)
end
end
end
end

69
lib/tasks/rspec.rake Normal file
View File

@ -0,0 +1,69 @@
begin
require 'rspec/core'
require 'rspec/core/rake_task'
rescue MissingSourceFile
module Rspec
module Core
class RakeTask
def initialize(name)
task name do
# if rspec-rails is a configured gem, this will output helpful material and exit ...
require File.expand_path(File.dirname(__FILE__) + "/../../config/environment")
# ... otherwise, do this:
raise <<-MSG
#{"*" * 80}
* You are trying to run an rspec rake task defined in
* #{__FILE__},
* but rspec can not be found in vendor/gems, vendor/plugins or system gems.
#{"*" * 80}
MSG
end
end
end
end
end
end
Rake.application.instance_variable_get('@tasks').delete('default')
spec_prereq = :noop #File.exist?(File.join(Rails.root, 'config', 'database.yml')) ? "db:test:prepare" : :noop
task :noop do
end
task :default => :spec
task :stats => "spec:statsetup"
desc "Run all specs in spec directory (excluding plugin specs)"
Rspec::Core::RakeTask.new(:spec => spec_prereq)
namespace :spec do
[:requests, :models, :controllers, :views, :helpers, :mailers, :lib].each do |sub|
desc "Run the code examples in spec/#{sub}"
Rspec::Core::RakeTask.new(sub => spec_prereq) do |t|
t.pattern = "./spec/#{sub}/**/*_spec.rb"
end
end
task :statsetup do
require 'rails/code_statistics'
::STATS_DIRECTORIES << %w(Model\ specs spec/models) if File.exist?('spec/models')
::STATS_DIRECTORIES << %w(View\ specs spec/views) if File.exist?('spec/views')
::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers) if File.exist?('spec/controllers')
::STATS_DIRECTORIES << %w(Helper\ specs spec/helpers) if File.exist?('spec/helpers')
::STATS_DIRECTORIES << %w(Library\ specs spec/lib) if File.exist?('spec/lib')
::STATS_DIRECTORIES << %w(Mailer\ specs spec/mailers) if File.exist?('spec/mailers')
::STATS_DIRECTORIES << %w(Routing\ specs spec/routing) if File.exist?('spec/routing')
::STATS_DIRECTORIES << %w(Request\ specs spec/requests) if File.exist?('spec/requests')
::CodeStatistics::TEST_TYPES << "Model specs" if File.exist?('spec/models')
::CodeStatistics::TEST_TYPES << "View specs" if File.exist?('spec/views')
::CodeStatistics::TEST_TYPES << "Controller specs" if File.exist?('spec/controllers')
::CodeStatistics::TEST_TYPES << "Helper specs" if File.exist?('spec/helpers')
::CodeStatistics::TEST_TYPES << "Library specs" if File.exist?('spec/lib')
::CodeStatistics::TEST_TYPES << "Mailer specs" if File.exist?('spec/mailer')
::CodeStatistics::TEST_TYPES << "Routing specs" if File.exist?('spec/routing')
::CodeStatistics::TEST_TYPES << "Request specs" if File.exist?('spec/requests')
end
end

17
spec/factories.rb Normal file
View File

@ -0,0 +1,17 @@
## Site ##
Factory.define :site do |s|
s.name 'Acme Website'
s.subdomain 'acme'
s.created_at Time.now
end
## Accounts ##
# Factory.define :account do |a|
# a.name 'Bart Simpson'
# a.email 'bart@fox.com'
# a.password 'easyone'
# a.password_confirmation 'easyone'
# a.locale 'en'
# end
## Site ##

24
spec/models/site_spec.rb Normal file
View File

@ -0,0 +1,24 @@
require 'spec_helper'
describe Site do
it 'should have a valid factory' do
Factory.build(:site).should be_valid
end
## Validations ##
it 'should validate presence of name' do
site = Factory.build(:site, :name => nil)
site.should_not be_valid
site.errors[:name].should == ["can't be blank"]
end
it 'should have a domain at minimum' do
site = Factory.build(:site, :subdomain => nil)
site.should_not be_valid
site.domains = %w{acme.net}
site.should be_valid
end
end

2
spec/spec.opts Normal file
View File

@ -0,0 +1,2 @@
--color
--format progress

24
spec/spec_helper.rb Normal file
View File

@ -0,0 +1,24 @@
# This file is copied to ~/spec when you run 'ruby script/generate rspec'
# from the project root directory.
ENV["RAILS_ENV"] ||= 'test'
require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
require 'rspec/rails'
# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
Rspec.configure do |config|
# == Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
config.mock_with :rspec
# If you'd prefer not to run each of your examples within a transaction,
# uncomment the following line.
# config.use_transactional_examples false
end

31
spec/support/be_valid.rb Normal file
View File

@ -0,0 +1,31 @@
module Spec
module Rails
module Matchers
class BeValid #:nodoc:
def matches?(model)
@model = model
@model.errors.clear
@model.errors.empty? && @model.valid?
end
def failure_message
"#{@model.class} expected to be valid but had errors:\n #{@model.errors.full_messages.join("\n ")}"
end
def negative_failure_message
"#{@model.class} expected to be invalid but was valid.\n"
end
def description
"be valid"
end
end
def be_valid
BeValid.new
end
end
end
end

View File

@ -1,9 +0,0 @@
require 'test_helper'
require 'rails/performance_test_help'
# Profiling results for each test method are written to tmp/performance.
class BrowsingTest < ActionController::PerformanceTest
def test_homepage
get '/'
end
end

View File

@ -1,13 +0,0 @@
ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'rails/test_help'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
# Add more helper methods to be used by all tests here...
end

1
tmp/remarkable_mongo Submodule

@ -0,0 +1 @@
Subproject commit 82eeed7945d911bc3a7bfc80e7fe615baa9c5c62

1
tmp/shoulda Submodule

@ -0,0 +1 @@
Subproject commit 46e70f6ef56b67b7712e23673a1beb63215f8dd5