toy-locomotive 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in toy-locomotive.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new('spec')
@@ -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
@@ -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,3 @@
1
+ module ToyLocomotive
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe ToyLocomotive do
4
+
5
+ it { should respond_to :routes }
6
+
7
+ end
@@ -0,0 +1,6 @@
1
+ require 'toy-locomotive'
2
+ require 'rspec-rails'
3
+
4
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: './toy_locomotive.sqlite3')
5
+
6
+ %w(schema models seeds controllers).each { |file| load "#{File.dirname(__FILE__)}/support/#{file}.rb" }
@@ -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: []