astaire 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.md +72 -0
  2. data/lib/astaire/railtie.rb +27 -0
  3. data/lib/astaire.rb +67 -12
  4. metadata +5 -4
  5. data/README +0 -3
data/README.md ADDED
@@ -0,0 +1,72 @@
1
+ ## Astaire: The basic Sinatra DSL for your Rails 3 apps
2
+
3
+ Astaire allows the use of the basic Sinatra get / post / put / delete
4
+ DSL inside of Rails controllers. This allows defining quick actions without
5
+ having to update config/routes.rb. For example:
6
+
7
+ class ContactController < ActionController::Base
8
+
9
+ get "/contact" do
10
+ render :contact_form
11
+ end
12
+
13
+ post "/contact" do
14
+ # handle form input
15
+ redirect_to homepage_path
16
+ end
17
+
18
+ end
19
+
20
+ ### Installation
21
+
22
+ Add the following to your application's Gemfile
23
+
24
+ gem "astaire"
25
+
26
+ Then, run `bundle install` and you are good to go.
27
+
28
+ ### Usage
29
+
30
+ Currently, Astaire provides 4 class level methods available in the
31
+ controller: `#get`, `#post`, `#put`, and `#delete`. With these methods
32
+ you can define actions and routes all at once.
33
+
34
+ class MyController < ActionController::Base
35
+
36
+ # Get the contact form
37
+ get "/contact" do
38
+ render :contact_form
39
+ end
40
+
41
+ # The paths can also have named parameters and
42
+ # optional segments
43
+ #
44
+ # /say/hello => "I say: hello"
45
+ # /say/hello/world => "I say: hello world"
46
+ #
47
+ get "/say/:one(/:two)" do
48
+ words = [params[:one], params[:two]].compact.join(' ')
49
+ render :text => "I say: #{words}"
50
+ end
51
+ end
52
+
53
+ It is possible to name actions such that regular URL helpers can generate them.
54
+
55
+ class MyController < ActionController::Base
56
+
57
+ # Will output /hello
58
+ def index
59
+ render :text => hello_path
60
+ end
61
+
62
+ get "/hello", :as => :hello do
63
+ render :text => "hello"
64
+ end
65
+
66
+ end
67
+
68
+ ### TODO
69
+
70
+ I guess, at this point I'm just putting what I have into the wild. Next
71
+ steps will be determined by feedback that I get. One thing that I would
72
+ like to add is Sinatra's inline template feature.
@@ -0,0 +1,27 @@
1
+ module Astaire
2
+ class Rails < Rails::Railtie
3
+ config.to_prepare do
4
+ ApplicationController.class_eval { include Astaire::DSL }
5
+ end
6
+
7
+ initializer "astaire.cascade_routing" do |app|
8
+ # A lambda is needed here to ensure that the constant is reloaded
9
+ # after each request (in development mode)
10
+ astaire_app = proc { |env| ApplicationController.call(env) }
11
+ app.middleware.use ActionDispatch::Cascade, lambda { astaire_app }
12
+ end
13
+
14
+ # Controllers must be preloaded in order for Astaire's routing
15
+ # to be hooked up
16
+ initializer "astaire.preload_controllers" do |app|
17
+ config.to_prepare do
18
+ app.config.paths.app.controllers.each do |load_path|
19
+ matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/
20
+ Dir["#{load_path}/**/*_controller.rb"].each do |file|
21
+ require_dependency file.sub(matcher, '\1')
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
data/lib/astaire.rb CHANGED
@@ -1,38 +1,93 @@
1
1
  require 'active_support/concern'
2
2
  require 'action_controller'
3
+ require 'astaire/railtie' if defined?(Rails)
3
4
 
4
5
  module Astaire
5
6
  module DSL
6
7
  extend ActiveSupport::Concern
7
8
 
9
+ include AbstractController::Helpers
10
+
8
11
  included do
9
- unless respond_to?(:_router)
10
- def self._router
11
- @_router ||= ActionDispatch::Routing::RouteSet.new
12
- end
13
- end
12
+ class_attribute :_astaire_router
13
+ self._astaire_router = ActionDispatch::Routing::RouteSet.new
14
+
15
+ class_attribute :_astaire_helpers
16
+ self._astaire_helpers = url_helper_module
17
+
18
+ include _astaire_helpers
19
+ helper _astaire_helpers
14
20
  end
15
21
 
16
22
  module ClassMethods
17
23
  def call(env)
18
- _router.call(env)
19
- rescue ActionController::RoutingError
20
- [404, {'Content-Type' => 'text/html', 'X-Cascade' => 'pass'}, []]
24
+ _astaire_router.call(env)
21
25
  end
22
26
 
23
27
  def mapper
24
- @mapper ||= ActionDispatch::Routing::Mapper.new(_router)
28
+ @mapper ||= ActionDispatch::Routing::Mapper.new(_astaire_router)
25
29
  end
26
30
 
27
31
  %w(get post put delete).each do |method|
28
32
  class_eval <<-R, __FILE__, __LINE__+1
29
33
  def #{method}(path, opts = {}, &blk)
30
- action_name = "[#{method}] \#{path}"
31
- define_method action_name, &blk
32
- mapper.match(path, :via => '#{method}', :to => action(action_name))
34
+ map_astaire_action "#{method}", path, opts, blk
33
35
  end
34
36
  R
35
37
  end
38
+
39
+ private
40
+
41
+ def map_astaire_action(method, path, opts, blk)
42
+ action_name = "[#{method}] #{path}"
43
+ define_method action_name, &blk
44
+ opts.merge! :via => method, :to => action(action_name)
45
+
46
+ mapper.match(path, opts)
47
+ make_url_helper(opts[:as]) if opts[:as]
48
+ end
49
+
50
+ def url_helper_module
51
+ Module.new do
52
+ def _astaire_url_opts_from_args(name, route, args, only_path)
53
+ opts = args.extract_options!
54
+
55
+ if args.any?
56
+ opts[:_positional_args] = args
57
+ opts[:_positional_keys] = route.segment_keys
58
+ end
59
+
60
+ opts = url_options.merge(opts)
61
+ opts.merge!(:use_route => name, :only_path => only_path)
62
+
63
+ if path_segments = opts[:_path_segments]
64
+ path_segments.delete(:controller)
65
+ path_segments.delete(:action)
66
+ end
67
+
68
+ opts
69
+ end
70
+ end
71
+ end
72
+
73
+ def make_url_helper(name)
74
+ name = name.to_sym
75
+ router = _astaire_router
76
+
77
+ _astaire_helpers.module_eval do
78
+ define_method "#{name}_path" do |*args|
79
+ route = router.named_routes[name]
80
+ opts = _astaire_url_opts_from_args(name, route, args, true)
81
+ router.url_for(opts)
82
+ end
83
+
84
+ define_method "#{name}_url" do |*args|
85
+ route = router.named_routes[name]
86
+ opts = _astaire_url_opts_from_args(name, route, args, false)
87
+ router.url_for(opts)
88
+ end
89
+ end
90
+ end
36
91
  end
37
92
  end
38
93
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
+ - 2
7
8
  - 0
8
- - 1
9
- version: 0.0.1
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Carl Lerche
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-01 00:00:00 -07:00
17
+ date: 2010-05-03 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -41,8 +41,9 @@ extensions: []
41
41
  extra_rdoc_files: []
42
42
 
43
43
  files:
44
- - README
44
+ - README.md
45
45
  - LICENSE
46
+ - lib/astaire/railtie.rb
46
47
  - lib/astaire.rb
47
48
  has_rdoc: true
48
49
  homepage: http://github.com/carllerche/astaire
data/README DELETED
@@ -1,3 +0,0 @@
1
- A first pass at the basic Sinatra DSL inside of a Rails controller. There is
2
- still a lot to do obviously, but see examples/hello_world.ru for a starting
3
- point.