toy-locomotive 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +3 -0
- data/lib/toy-locomotive/.initializer.rb.swp +0 -0
- data/lib/toy-locomotive/initializer.rb +14 -0
- data/lib/toy-locomotive/router/.controller.rb.swp +0 -0
- data/lib/toy-locomotive/router/.model.rb.swp +0 -0
- data/lib/toy-locomotive/router/controller.rb +100 -0
- data/lib/toy-locomotive/router/model.rb +40 -0
- data/lib/toy-locomotive/version.rb +3 -0
- data/lib/toy-locomotive.rb +13 -0
- data/spec/lib/router_controller_spec.rb +71 -0
- data/spec/lib/router_model_spec.rb +49 -0
- data/spec/lib/toy_locomotive_spec.rb +7 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/controllers.rb +30 -0
- data/spec/support/models.rb +16 -0
- data/spec/support/schema.rb +19 -0
- data/spec/support/seeds.rb +1 -0
- data/toy-locomotive.gemspec +28 -0
- metadata +109 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
Binary file
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ToyLocomotive
|
2
|
+
class Engine < Rails::Engine
|
3
|
+
initializer 'toy_locomotive.initialize', :after=> :disable_dependency_loading do |app|
|
4
|
+
Dir["#{Rails.root}/app/models/*.rb"].each {|file| require file}
|
5
|
+
Dir["#{Rails.root}/app/controllers/*.rb"].each do |file|
|
6
|
+
require file
|
7
|
+
const = file.split('/').last.split('.').first.classify.constantize.append_filters!
|
8
|
+
end
|
9
|
+
Rails.application.class.routes.draw do
|
10
|
+
ToyLocomotive.routes.each {|route| match route[:path] => "#{route[:controller]}##{route[:action]}", as: route[:as], via: route[:method]}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module ToyLocomotive::Router::Controller
|
2
|
+
|
3
|
+
module ClassMethods
|
4
|
+
|
5
|
+
%w(get put post delete).each {|via| eval "def #{via} path, opts={}, &blk; match_action \"#{via}\", path, opts, blk; end"}
|
6
|
+
|
7
|
+
def match_action method, path, opts, blk
|
8
|
+
action = extract_action path, opts
|
9
|
+
extract_filter action, path, opts
|
10
|
+
path = extract_path path, opts
|
11
|
+
as = extract_as path, opts
|
12
|
+
controller = extract_controller
|
13
|
+
add_route method, action, path, as, controller
|
14
|
+
define_method action, blk
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_route method, action, path, as, controller
|
18
|
+
ToyLocomotive.routes ||= []
|
19
|
+
ToyLocomotive.routes << {method: method, action: action, path: path, controller: controller, as: as}
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_member_filter action
|
23
|
+
@member_filters ||= []
|
24
|
+
@member_filters << action.to_sym
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_collection_filter action
|
28
|
+
@collection_filters ||= []
|
29
|
+
@collection_filters << action.to_sym
|
30
|
+
end
|
31
|
+
|
32
|
+
def extract_path path, opts={}
|
33
|
+
path[0] == '/' ? path : "#{extract_model.route_chain}#{opts[:on] == 'member' ? extract_model.to_route : "/#{extract_model.to_s.underscore.pluralize}"}/#{path.parameterize}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def extract_as path, opts={}
|
37
|
+
action = extract_action path, opts
|
38
|
+
path[0] == '/' ? action : "#{action}_#{extract_model.to_as}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def extract_action path, opts={}
|
42
|
+
(opts[:as] || (path == '/' ? 'root' : path)).parameterize.underscore
|
43
|
+
end
|
44
|
+
|
45
|
+
def extract_controller
|
46
|
+
to_s.gsub('Controller', '').downcase
|
47
|
+
end
|
48
|
+
|
49
|
+
def extract_model
|
50
|
+
extract_controller.singularize.camelize.constantize
|
51
|
+
end
|
52
|
+
|
53
|
+
def extract_filter action, path, opts
|
54
|
+
return if path[0] == '/'
|
55
|
+
send :"add_#{opts[:on]}_filter", action
|
56
|
+
end
|
57
|
+
|
58
|
+
def append_filters!
|
59
|
+
before_filter :extract_parent_vars, only: ((@member_filters || []) + (@collection_filters || []))
|
60
|
+
before_filter :extract_member_var, only: (@member_filters || [])
|
61
|
+
before_filter :extract_collection_var, only: (@collection_filters || [])
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
module InstanceMethods
|
67
|
+
|
68
|
+
def extract_parent_vars
|
69
|
+
chain = self.class.extract_model.belongs_chain
|
70
|
+
vars = []
|
71
|
+
if chain.any?
|
72
|
+
root = chain.pop
|
73
|
+
parent = root.find(params[root.to_params])
|
74
|
+
instance_variable_set root.to_member_var, parent
|
75
|
+
vars << parent
|
76
|
+
chain.reverse!.each do |model|
|
77
|
+
parent = parent.send(model.to_s.underscore.pluralize).find(params[model.to_params])
|
78
|
+
instance_variable_set model.to_member_var, parent
|
79
|
+
vars << parent
|
80
|
+
end
|
81
|
+
end
|
82
|
+
vars
|
83
|
+
end
|
84
|
+
|
85
|
+
def extract_member_var
|
86
|
+
parent = instance_variable_get (model = self.class.extract_model).belongs_chain.reverse.pop.to_member_var
|
87
|
+
parent ? instance_variable_set(model.to_member_var, parent.send(model.to_s.underscore.pluralize).find(params[model.to_params])) : model.find(params[model.to_params])
|
88
|
+
end
|
89
|
+
|
90
|
+
def extract_collection_var
|
91
|
+
parent = instance_variable_get (model = self.class.extract_model).belongs_chain.reverse.pop.to_member_var
|
92
|
+
parent ? instance_variable_set(model.to_collection_var, parent.send(model.to_s.underscore.pluralize)) : model.all
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
ActionController::Base.extend ToyLocomotive::Router::Controller::ClassMethods
|
100
|
+
ActionController::Base.send :include, ToyLocomotive::Router::Controller::InstanceMethods
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ToyLocomotive::Router::Model
|
2
|
+
|
3
|
+
def belongs_to_route
|
4
|
+
reflections = reflect_on_all_associations(:belongs_to)
|
5
|
+
reflections.any? ? reflections.first.name.to_s.camelize.constantize : nil
|
6
|
+
end
|
7
|
+
|
8
|
+
def belongs_chain chain=[]
|
9
|
+
parent_route = (chain.last || self).belongs_to_route
|
10
|
+
parent_route ? belongs_chain(chain << parent_route) : chain
|
11
|
+
end
|
12
|
+
|
13
|
+
def route_chain
|
14
|
+
belongs_chain.reverse.map{|m| m.to_route}.join
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_route
|
18
|
+
s = to_s.parameterize.downcase
|
19
|
+
"/#{s.pluralize}/:#{s}_id"
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_member_var
|
23
|
+
"@#{to_s.underscore}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_collection_var
|
27
|
+
to_member_var.pluralize
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_params
|
31
|
+
:"#{to_s.underscore}_id"
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_as
|
35
|
+
belongs_chain.reverse!.map{|m| m.to_s.underscore }.join('_') << (belongs_chain.empty? ? to_s.underscore : "_#{to_s.underscore}")
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
ActiveRecord::Base.extend ToyLocomotive::Router::Model
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "rails/all"
|
2
|
+
require "toy-locomotive/version"
|
3
|
+
|
4
|
+
module ToyLocomotive
|
5
|
+
|
6
|
+
module Router; end
|
7
|
+
mattr_accessor :routes
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
require "toy-locomotive/router/model"
|
12
|
+
require "toy-locomotive/router/controller"
|
13
|
+
require "toy-locomotive/initializer"
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DogsController do
|
4
|
+
|
5
|
+
subject { DogsController }
|
6
|
+
|
7
|
+
its(:extract_model) {should == Dog}
|
8
|
+
its(:extract_controller) {should == 'dogs'}
|
9
|
+
|
10
|
+
[:get, :put, :post, :delete].each {|via| it { should respond_to(via) }}
|
11
|
+
|
12
|
+
it "extracts vars" do
|
13
|
+
dog_controller = DogsController.new
|
14
|
+
dog_controller.extract_parent_vars[0].class.should == Alien
|
15
|
+
dog_controller.extract_parent_vars[1].class.should == Human
|
16
|
+
dog_controller.extract_member_var.class.should == Dog
|
17
|
+
dog_controller.extract_collection_var.class.should == Array
|
18
|
+
dog_controller.extract_collection_var.first.class.should == Dog
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.extract_action' do
|
22
|
+
it "recognizes the root" do
|
23
|
+
DogsController.extract_action('/').should == 'root'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns the option :as if declared" do
|
27
|
+
DogsController.extract_action('lorem-ipsum', as: 'dolor-sit').should == 'dolor_sit'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns the path if no options" do
|
31
|
+
DogsController.extract_action('lorem-ipsum').should == 'lorem_ipsum'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.extract_as' do
|
36
|
+
it "returns the action if its absolute path" do
|
37
|
+
DogsController.extract_as('/lorem-ipsum').should == 'lorem_ipsum'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns the chain as method if its relative path" do
|
41
|
+
DogsController.extract_as('lorem').should == 'lorem_alien_human_dog'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '.extract_path' do
|
46
|
+
it "returns itself if absolute path" do
|
47
|
+
DogsController.extract_path('/lorem').should == '/lorem'
|
48
|
+
end
|
49
|
+
|
50
|
+
it "matches relative path on member" do
|
51
|
+
DogsController.extract_path('lorem', on: 'member').should == '/aliens/:alien_id/humans/:human_id/dogs/:dog_id/lorem'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "matches relative path on collection" do
|
55
|
+
DogsController.extract_path('lorem', on: 'collection').should == '/aliens/:alien_id/humans/:human_id/dogs/lorem'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '.get' do
|
60
|
+
it "adds a empty method" do
|
61
|
+
DogsController.get('/lorem'){}
|
62
|
+
DogsController.new.should respond_to(:lorem)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "adds a method from a block" do
|
66
|
+
DogsController.get('/lorem') { 'lorem-ipsum' }
|
67
|
+
DogsController.new.lorem.should == 'lorem-ipsum'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Dog do
|
4
|
+
|
5
|
+
subject { Dog }
|
6
|
+
|
7
|
+
{ to_params: :dog_id,
|
8
|
+
to_collection_var: '@dogs',
|
9
|
+
to_member_var: '@dog',
|
10
|
+
to_route: '/dogs/:dog_id',
|
11
|
+
route_chain: '/aliens/:alien_id/humans/:human_id',
|
12
|
+
belongs_chain: [Human, Alien],
|
13
|
+
belongs_to_route: Human,
|
14
|
+
to_as: 'alien_human_dog'
|
15
|
+
}.each{|method, expectation| its(method) {should == expectation}}
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Human do
|
20
|
+
|
21
|
+
subject { Human }
|
22
|
+
|
23
|
+
{ to_params: :human_id,
|
24
|
+
to_collection_var: '@humans',
|
25
|
+
to_member_var: '@human',
|
26
|
+
to_route: '/humans/:human_id',
|
27
|
+
route_chain: '/aliens/:alien_id',
|
28
|
+
belongs_chain: [Alien],
|
29
|
+
belongs_to_route: Alien,
|
30
|
+
to_as: 'alien_human'
|
31
|
+
}.each{|method, expectation| its(method) {should == expectation}}
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Alien do
|
36
|
+
|
37
|
+
subject { Alien }
|
38
|
+
|
39
|
+
{ to_params: :alien_id,
|
40
|
+
to_collection_var: '@aliens',
|
41
|
+
to_member_var: '@alien',
|
42
|
+
to_route: '/aliens/:alien_id',
|
43
|
+
route_chain: '',
|
44
|
+
belongs_chain: [],
|
45
|
+
belongs_to_route: nil,
|
46
|
+
to_as: 'alien'
|
47
|
+
}.each{|method, expectation| its(method) {should == expectation}}
|
48
|
+
|
49
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
class DogsController < ActionController::Base
|
2
|
+
|
3
|
+
def params
|
4
|
+
{alien_id: Alien.first.id, human_id: Human.first.id, dog_id: Dog.first.id}
|
5
|
+
end
|
6
|
+
|
7
|
+
get '/absolute' do
|
8
|
+
'absolute route'
|
9
|
+
end
|
10
|
+
|
11
|
+
get 'member', on: 'member' do
|
12
|
+
'member route'
|
13
|
+
end
|
14
|
+
|
15
|
+
get 'collection', on: 'collection' do
|
16
|
+
'collection route'
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
DogsController.append_filters!
|
21
|
+
|
22
|
+
class HumansController < ActionController::Base
|
23
|
+
|
24
|
+
end
|
25
|
+
HumansController.append_filters!
|
26
|
+
|
27
|
+
class AliensController < ActionController::Base
|
28
|
+
|
29
|
+
end
|
30
|
+
AliensController.append_filters!
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Dog < ActiveRecord::Base
|
2
|
+
belongs_to :human
|
3
|
+
end
|
4
|
+
|
5
|
+
class Human < ActiveRecord::Base
|
6
|
+
belongs_to :alien
|
7
|
+
has_many :dogs
|
8
|
+
end
|
9
|
+
|
10
|
+
class Alien < ActiveRecord::Base
|
11
|
+
has_many :humans
|
12
|
+
end
|
13
|
+
|
14
|
+
ActiveSupport::Inflector.inflections do |inflect|
|
15
|
+
inflect.irregular 'Human', 'Humans'
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
ActiveRecord::Schema.define do
|
2
|
+
|
3
|
+
self.verbose = false
|
4
|
+
|
5
|
+
create_table :dogs, :force => true do |t|
|
6
|
+
t.integer :human_id
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :humans, :force => true do |t|
|
11
|
+
t.integer :alien_id
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :aliens, :force => true do |t|
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Alien.create.humans.create.dogs.create
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "toy-locomotive/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
|
7
|
+
s.name = "toy-locomotive"
|
8
|
+
s.version = ToyLocomotive::VERSION
|
9
|
+
s.authors = ["Christian Mortaro"]
|
10
|
+
s.email = ["mortaro@towsta.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{a Toy Locomotive to run over Rails}
|
13
|
+
s.description = %q{a Different aproach to Rails applications}
|
14
|
+
|
15
|
+
s.rubyforge_project = "toy-locomotive"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency "rails"
|
23
|
+
|
24
|
+
s.add_development_dependency "rspec-rails"
|
25
|
+
s.add_development_dependency "sqlite3"
|
26
|
+
s.add_development_dependency "shoulda"
|
27
|
+
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: toy-locomotive
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Christian Mortaro
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: &22779288 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *22779288
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec-rails
|
27
|
+
requirement: &22778760 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *22778760
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: sqlite3
|
38
|
+
requirement: &22778280 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *22778280
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: shoulda
|
49
|
+
requirement: &22777812 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *22777812
|
58
|
+
description: a Different aproach to Rails applications
|
59
|
+
email:
|
60
|
+
- mortaro@towsta.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- .gitignore
|
66
|
+
- Gemfile
|
67
|
+
- Rakefile
|
68
|
+
- lib/toy-locomotive.rb
|
69
|
+
- lib/toy-locomotive/.initializer.rb.swp
|
70
|
+
- lib/toy-locomotive/initializer.rb
|
71
|
+
- lib/toy-locomotive/router/.controller.rb.swp
|
72
|
+
- lib/toy-locomotive/router/.model.rb.swp
|
73
|
+
- lib/toy-locomotive/router/controller.rb
|
74
|
+
- lib/toy-locomotive/router/model.rb
|
75
|
+
- lib/toy-locomotive/version.rb
|
76
|
+
- spec/lib/router_controller_spec.rb
|
77
|
+
- spec/lib/router_model_spec.rb
|
78
|
+
- spec/lib/toy_locomotive_spec.rb
|
79
|
+
- spec/spec_helper.rb
|
80
|
+
- spec/support/controllers.rb
|
81
|
+
- spec/support/models.rb
|
82
|
+
- spec/support/schema.rb
|
83
|
+
- spec/support/seeds.rb
|
84
|
+
- toy-locomotive.gemspec
|
85
|
+
homepage: ''
|
86
|
+
licenses: []
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubyforge_project: toy-locomotive
|
105
|
+
rubygems_version: 1.8.16
|
106
|
+
signing_key:
|
107
|
+
specification_version: 3
|
108
|
+
summary: a Toy Locomotive to run over Rails
|
109
|
+
test_files: []
|