astaire 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.