macournoyer-invisible 0.0.1

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 (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