macournoyer-invisible 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/README +63 -0
  2. data/Rakefile +64 -0
  3. data/app_generators/flat/flat_generator.rb +40 -0
  4. data/app_generators/flat/templates/README +10 -0
  5. data/app_generators/flat/templates/app.rb +16 -0
  6. data/app_generators/flat/templates/rack.ru +17 -0
  7. data/app_generators/full/full_generator.rb +80 -0
  8. data/app_generators/full/templates/README +10 -0
  9. data/app_generators/full/templates/Rakefile +16 -0
  10. data/app_generators/full/templates/app.rb +7 -0
  11. data/app_generators/full/templates/config/boot.rb +5 -0
  12. data/app_generators/full/templates/config/env.rb +18 -0
  13. data/app_generators/full/templates/config/env/development.rb +6 -0
  14. data/app_generators/full/templates/config/env/production.rb +7 -0
  15. data/app_generators/full/templates/config/env/test.rb +1 -0
  16. data/app_generators/full/templates/config/rack.ru +6 -0
  17. data/app_generators/full/templates/gitignore +3 -0
  18. data/app_generators/full/templates/public/stylesheets/ie.css +16 -0
  19. data/app_generators/full/templates/public/stylesheets/print.css +21 -0
  20. data/app_generators/full/templates/public/stylesheets/screen.css +242 -0
  21. data/app_generators/full/templates/spec/app_spec.rb +7 -0
  22. data/app_generators/full/templates/spec/spec_helper.rb +14 -0
  23. data/app_generators/full/templates/test/app_test.rb +7 -0
  24. data/app_generators/full/templates/test/test_helper.rb +15 -0
  25. data/app_generators/full/templates/views/layout.erb +18 -0
  26. data/bin/invisible +18 -0
  27. data/invisible.gemspec +119 -0
  28. data/lib/invisible.rb +212 -0
  29. data/lib/invisible/core_ext.rb +12 -0
  30. data/lib/invisible/erb.rb +16 -0
  31. data/lib/invisible/erubis.rb +14 -0
  32. data/lib/invisible/haml.rb +14 -0
  33. data/lib/invisible/helpers.rb +5 -0
  34. data/lib/invisible/mock.rb +20 -0
  35. data/lib/invisible/reloader.rb +22 -0
  36. metadata +119 -0
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ describe "app" do
4
+ it "should get /" do
5
+ get("/").should be_ok
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ ENV["RACK_ENV"] = "test"
2
+ require File.dirname(__FILE__) + "/../config/boot"
3
+ require "invisible/mock"
4
+ require "spec"
5
+
6
+ Spec::Runner.configure do |config|
7
+ config.prepend_before do
8
+ @app = Invisible.new do
9
+ root File.dirname(__FILE__) + "/.."
10
+ load "config/env"
11
+ end
12
+ end
13
+ config.include Invisible::MockMethods
14
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + "/test_helper"
2
+
3
+ class AppTest < Test::Unit::TestCase
4
+ def test_should_get_root
5
+ assert get("/").ok?
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ ENV["RACK_ENV"] = "test"
2
+ require File.dirname(__FILE__) + "/../config/boot"
3
+ require "invisible/mock"
4
+ require "test/unit"
5
+
6
+ class Test::Unit::TestCase
7
+ include Invisible::MockMethods
8
+
9
+ def setup
10
+ @app = Invisible.new do
11
+ root File.dirname(__FILE__) + "/.."
12
+ load "config/env"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
3
+ <head>
4
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
5
+ <title>Invisible</title>
6
+ <link rel="stylesheet" href="/stylesheets/screen.css" type="text/css" media="screen, projection" />
7
+ <link rel="stylesheet" href="/stylesheets/print.css" type="text/css" media="print" />
8
+ <!--[if IE]>
9
+ <link rel="stylesheet" href="/stylesheets/ie.css" type="text/css" media="screen, projection" />
10
+ <![endif]-->
11
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js" />
12
+ </head>
13
+ <body>
14
+ <div id="content" class="container">
15
+ <%= @content %>
16
+ </div>
17
+ </body>
18
+ </html>
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'rubigen'
5
+
6
+ require 'rubigen/scripts/generate'
7
+ source = RubiGen::PathSource.new(:application,
8
+ File.join(File.dirname(__FILE__), "../app_generators"))
9
+ RubiGen::Base.reset_sources
10
+ RubiGen::Base.append_sources source
11
+
12
+ if ARGV.delete("--flat")
13
+ generator = "flat"
14
+ else
15
+ generator = "full"
16
+ end
17
+
18
+ RubiGen::Scripts::Generate.new.run(ARGV, :generator => generator)
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: invisible
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Marc-Andre Cournoyer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-11-12 00:00:00 -05:00
13
+ default_executable: invisible
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rack
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.4.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: markaby
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0.5"
34
+ version:
35
+ description: Invisible is like a giant robot combining the awesomeness of Rails, Merb, Camping and Sinatra. Except, it's tiny (100 sloc).
36
+ email: macournoyer@gmail.com
37
+ executables:
38
+ - invisible
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README
43
+ files:
44
+ - README
45
+ - Rakefile
46
+ - invisible.gemspec
47
+ - bin/invisible
48
+ - lib/invisible
49
+ - lib/invisible/core_ext.rb
50
+ - lib/invisible/erb.rb
51
+ - lib/invisible/erubis.rb
52
+ - lib/invisible/haml.rb
53
+ - lib/invisible/helpers.rb
54
+ - lib/invisible/mock.rb
55
+ - lib/invisible/reloader.rb
56
+ - lib/invisible.rb
57
+ - app_generators/flat
58
+ - app_generators/flat/flat_generator.rb
59
+ - app_generators/flat/templates
60
+ - app_generators/flat/templates/app.rb
61
+ - app_generators/flat/templates/rack.ru
62
+ - app_generators/flat/templates/README
63
+ - app_generators/full
64
+ - app_generators/full/full_generator.rb
65
+ - app_generators/full/templates
66
+ - app_generators/full/templates/app.rb
67
+ - app_generators/full/templates/config
68
+ - app_generators/full/templates/config/boot.rb
69
+ - app_generators/full/templates/config/env
70
+ - app_generators/full/templates/config/env/development.rb
71
+ - app_generators/full/templates/config/env/production.rb
72
+ - app_generators/full/templates/config/env/test.rb
73
+ - app_generators/full/templates/config/env.rb
74
+ - app_generators/full/templates/config/rack.ru
75
+ - app_generators/full/templates/gitignore
76
+ - app_generators/full/templates/public
77
+ - app_generators/full/templates/public/stylesheets
78
+ - app_generators/full/templates/public/stylesheets/ie.css
79
+ - app_generators/full/templates/public/stylesheets/print.css
80
+ - app_generators/full/templates/public/stylesheets/screen.css
81
+ - app_generators/full/templates/Rakefile
82
+ - app_generators/full/templates/README
83
+ - app_generators/full/templates/spec
84
+ - app_generators/full/templates/spec/app_spec.rb
85
+ - app_generators/full/templates/spec/spec_helper.rb
86
+ - app_generators/full/templates/test
87
+ - app_generators/full/templates/test/app_test.rb
88
+ - app_generators/full/templates/test/test_helper.rb
89
+ - app_generators/full/templates/views
90
+ - app_generators/full/templates/views/layout.erb
91
+ has_rdoc: true
92
+ homepage: http://github.com/macournoyer/invisible
93
+ post_install_message:
94
+ rdoc_options:
95
+ - --main
96
+ - README
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: "0"
104
+ version:
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: "0"
110
+ version:
111
+ requirements: []
112
+
113
+ rubyforge_project:
114
+ rubygems_version: 1.2.0
115
+ signing_key:
116
+ specification_version: 2
117
+ summary: The Invisible Web Framework
118
+ test_files: []
119
+
@@ -0,0 +1,212 @@
1
+ %w(rubygems time rack markaby invisible/core_ext invisible/helpers).each { |f| require f }
2
+ # = The Invisible Framework
3
+ # Invisible is like a giant robot combining the awesomeness of Rails,
4
+ # Merb, Camping and Sinatra. Except, it's tiny (100 sloc).
5
+ #
6
+ # == Build an app in an object
7
+ # Invisible supports multiple applications running in the same VM. Each instance
8
+ # of this class represents a runnable application.
9
+ #
10
+ # app = Invisible.new do
11
+ # get "/" do
12
+ # render "ohaie"
13
+ # end
14
+ # end
15
+ #
16
+ # You can then run it as a Rack application.
17
+ #
18
+ # run app
19
+ #
20
+ class Invisible
21
+ HTTP_METHODS = [:get, :post, :head, :put, :delete]
22
+ attr_reader :actions, :request, :response, :params
23
+
24
+ # Creates a new Invisible Rack application. You can build your app
25
+ # in the yielded block or using the app instance.
26
+ def initialize(&block)
27
+ @actions, @with, @loaded, @layouts, @views, @helpers, @app = [], [], [], {}, {}, self, method(:_call)
28
+ @root = File.dirname(eval("__FILE__", block.binding))
29
+ instance_eval(&block)
30
+ end
31
+
32
+ # Set the root of the app.
33
+ # Defaults to the file the Invisible class is instancianted in.
34
+ def root(value=@root)
35
+ @root = value
36
+ end
37
+
38
+ # Register an action for a specified +route+.
39
+ #
40
+ # get "/" do
41
+ # # ...
42
+ # end
43
+ #
44
+ def action(method, route, &block)
45
+ @actions << [method.to_s, build_route(@with * "/" + route), block]
46
+ end
47
+ HTTP_METHODS.each { |m| class_eval "def #{m}(r='/',&b); action('#{m}', r, &b) end" }
48
+
49
+ # Wrap actions sharing a common base route.
50
+ #
51
+ # with "/lol" do
52
+ # get "/cat" # ...
53
+ # end
54
+ #
55
+ # Will register an action on GET /lol/cat.
56
+ # You can nested as many level as you want.
57
+ def with(route)
58
+ @with.push(route)
59
+ yield
60
+ @with.pop
61
+ end
62
+
63
+ # Render the response inside an action.
64
+ # Render markaby by passing a block:
65
+ #
66
+ # render do
67
+ # h1 "Poop"
68
+ # p "Smells!"
69
+ # end
70
+ #
71
+ # or simple text as the first argument:
72
+ #
73
+ # render "crap"
74
+ #
75
+ # or render a markaby view, created using the +view+ method:
76
+ #
77
+ # view :lolcat do
78
+ # p "i can has?"
79
+ # end
80
+ # render :lolcat
81
+ #
82
+ # You can also pass some options or headers:
83
+ #
84
+ # render "heck", :status => 201, :layout => :none, 'X-Crap-Level' => 'ubersome'
85
+ #
86
+ # Supported options are:
87
+ # status: Status code of the response.
88
+ # layout: Name of the layout to use.
89
+ # All other options will be sent as a response header.
90
+ def render(*args, &block)
91
+ options = args.last.is_a?(Hash) ? args.pop : {}
92
+
93
+ # Extract options
94
+ layout = @layouts[options.delete(:layout) || :default]
95
+ @response.status = options.delete(:status) || 200
96
+
97
+ # Render inside the layout
98
+ @content = args.last.is_a?(String) ? args.last : mab(&(block || @views[args.last]))
99
+ @content = mab(&layout).to_s if layout
100
+
101
+ # Set headers
102
+ @response.headers.merge!(options)
103
+ @response.headers["Content-Length"] ||= @content.size.to_s
104
+ @response.headers["Last-Modified"] ||= Time.now.httpdate
105
+ @response.body = @content
106
+ end
107
+
108
+ # Redirect to a path.
109
+ #
110
+ # redirect_to "/login"
111
+ #
112
+ # To do a permanent redirect, specify the status code as the last argument.
113
+ #
114
+ # redirect_to "/", 301
115
+ #
116
+ def redirect_to(path, status=302)
117
+ render(:status => status, "Location" => path) { p { text("You are redirected to "); a(path, :href => path) } }
118
+ end
119
+
120
+ # Register a layout to be used around +render+ed text.
121
+ # Use markaby inside your block.
122
+ def layout(name=:default, &block)
123
+ @layouts[name] = block
124
+ end
125
+
126
+ # Register a named view to be used from <tt>render :name</tt>.
127
+ # Use markaby inside your block.
128
+ def view(name, &block)
129
+ @views[name] = block
130
+ end
131
+
132
+ # Return HTML rendered by evaluating the block using Markaby.
133
+ def mab(&block)
134
+ Markaby::Builder.new({}, self, &block).to_s
135
+ end
136
+
137
+ # Return the current session.
138
+ # Add `use Rack::Session::Cookie` to use.
139
+ def session
140
+ @request.env["rack.session"]
141
+ end
142
+
143
+ # Register a Rack middleware wrapping the
144
+ # current application.
145
+ def use(middleware, *args)
146
+ @app = middleware.new(@app, *args)
147
+ end
148
+
149
+ # Called by the Rack handler to process a request.
150
+ def call(env)
151
+ @app.call(env)
152
+ end
153
+
154
+ # Load an external file inside the context of Invisible,
155
+ # which means you can use the get,post,with methods.
156
+ # The files loaded with this method will be reloaded in
157
+ # You're using the Invisible Reloader middleware.
158
+ # Options:
159
+ # reload: false to not reload the file when Reloader middleware is in use.
160
+ # (default: true)
161
+ def load(file, options={})
162
+ return if @loaded.include?(file)
163
+ @loaded << file unless FalseClass === options[:reload]
164
+ path = File.join(@root, file) + ".rb"
165
+ eval(File.read(path), binding, path)
166
+ end
167
+
168
+ # Shortcut to Rack builder +run+ method.
169
+ # Equivalent to:
170
+ #
171
+ # app = Invisible.new do
172
+ # ...
173
+ # end
174
+ # run app
175
+ #
176
+ def self.run(*args, &block)
177
+ eval("self", block.binding).run new(&block)
178
+ end
179
+
180
+ private
181
+ def _call(env)
182
+ @request = Rack::Request.new(env)
183
+ @response = Rack::Response.new
184
+ @params = @request.params.symbolize_keys
185
+ if action = recognize(@request.path_info, @request.POST["_method"] || @request.request_method)
186
+ @params.merge!(@path_params)
187
+ instance_eval(&action.last)
188
+ else
189
+ @response.status = 404
190
+ @response.body = "Not found"
191
+ end
192
+ @response.finish
193
+ end
194
+
195
+ def build_route(route)
196
+ pattern = '\/*' + route.gsub("*", '.*').gsub("/", '\/*').gsub(/:\w+/, '(\w+)') + '\/*'
197
+ [/^#{pattern}$/i, route.scan(/\:(\w+)/).flatten]
198
+ end
199
+
200
+ def recognize(url, method)
201
+ method = method.to_s.downcase
202
+ @actions.detect do |m, (pattern, keys), _|
203
+ method == m && @path_params = match_route(pattern, keys, url)
204
+ end
205
+ end
206
+
207
+ def match_route(pattern, keys, url)
208
+ matches, params = (url.match(pattern) || return)[1..-1], {}
209
+ keys.each_with_index { |key, i| params[key] = matches[i] }
210
+ params.symbolize_keys
211
+ end
212
+ end
@@ -0,0 +1,12 @@
1
+ # Mostly taken from ActiveSupport
2
+ unless defined?(ActiveSupport)
3
+ class Hash
4
+ # Return a new hash with all keys converted to symbols.
5
+ def symbolize_keys
6
+ inject({}) do |options, (key, value)|
7
+ options[(key.to_sym rescue key) || key] = value
8
+ options
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ require "erb"
2
+
3
+ class Invisible
4
+ include ERB::Util
5
+
6
+ # Evaluate the ERB template in +file+ and returns the
7
+ # result as a string.
8
+ # Use with +render+:
9
+ #
10
+ # render erb(:muffin)
11
+ #
12
+ def erb(file)
13
+ path = File.join(@root, "views", file.to_s)
14
+ ERB.new(File.read("#{path}.erb")).result(binding)
15
+ end
16
+ end