monoriel 0.1.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.
- data/README.md +113 -0
- data/lib/monoriel.rb +113 -0
- data/monoriel.gemspec +13 -0
- data/sample/app.rb +139 -0
- data/sample/config.ru +7 -0
- data/sample/public/css/layout.css +3 -0
- data/sample/public/js/common.js +1 -0
- data/sample/views/index.erb +8 -0
- data/sample/views/index.haml +9 -0
- data/sample/views/index.slim +11 -0
- data/sample/views/index.slim~ +11 -0
- data/test/monoriel-test.rb +203 -0
- metadata +72 -0
data/README.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
>There must be some way out of here
|
2
|
+
>said the programmer to the chief
|
3
|
+
>there's too much confusion
|
4
|
+
>i can get no release -- Bob Dylan
|
5
|
+
|
6
|
+
MonoRiel
|
7
|
+
=====
|
8
|
+
|
9
|
+
MonoRiel is an attempt to fork from mini-rail
|
10
|
+
which is in itself a fork from another rack project(rack-golem) into
|
11
|
+
super simplistic but useful web mini-framework (MonoRiel (spanish) = monorail (english))
|
12
|
+
|
13
|
+
there's no gem for now, but somewhere in time you will:
|
14
|
+
|
15
|
+
sudo gem install monoriel
|
16
|
+
|
17
|
+
You can use config.ru as a start up file as for any rack app based
|
18
|
+
|
19
|
+
require 'models' # Loads your models and all ORM stuff
|
20
|
+
require 'app' # This is the main file
|
21
|
+
use Rack::ContentLength
|
22
|
+
use Rack::Session::Cookies
|
23
|
+
use Rack::Static, urls: ["/css","/js","/html"], root: "public" #Add this for static content
|
24
|
+
#The default folder for templates is views
|
25
|
+
run Rack::MethodOverride.new(App.new) #Need to use this for PUT and DELETE methods
|
26
|
+
|
27
|
+
Now save this into app.rb
|
28
|
+
|
29
|
+
require 'monoriel'
|
30
|
+
|
31
|
+
class App
|
32
|
+
include Monoriel # No classes to inherit just mixin
|
33
|
+
|
34
|
+
before do
|
35
|
+
# Here you can do many things
|
36
|
+
# In order to help you here are some variables you can read and override:
|
37
|
+
# @r => the Rack::Request object
|
38
|
+
# @res => the Rack::Response object
|
39
|
+
# @action => Name of the public method that will handle the request
|
40
|
+
@user.login
|
41
|
+
end
|
42
|
+
|
43
|
+
helpers do
|
44
|
+
#altough you can write many things in the before block
|
45
|
+
#you always need helpers for your main app
|
46
|
+
def help(with)
|
47
|
+
"Helping the World!" + with
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def index(*args)
|
52
|
+
# Used always when no public method is found
|
53
|
+
# Of course you don't have to declare one and it is gonna use #not_found instead
|
54
|
+
# Still can have arguments
|
55
|
+
@articles = Post.all
|
56
|
+
erb :index
|
57
|
+
end
|
58
|
+
|
59
|
+
def page(id=nil)
|
60
|
+
@page = Pages[id]
|
61
|
+
if @page.nil?
|
62
|
+
not_found
|
63
|
+
else
|
64
|
+
erb :page
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def form
|
69
|
+
#write your form here
|
70
|
+
#add _method hidden PUT as the Form Action
|
71
|
+
end
|
72
|
+
|
73
|
+
def post_page
|
74
|
+
#You can POST Forms and Monoriel will direct to post_* methods
|
75
|
+
@r.params["name"]
|
76
|
+
end
|
77
|
+
|
78
|
+
def best_restaurants_json
|
79
|
+
# Monoriel replaces dashes with underscores
|
80
|
+
# You can trigger this handler by visiting /best-restaurants-json
|
81
|
+
json_response({
|
82
|
+
'title' => 'Best restaurants in town',
|
83
|
+
'list' => Restaurant.full_list
|
84
|
+
})
|
85
|
+
|
86
|
+
def say(listener='me', *words)
|
87
|
+
"Hey #{listener} I don't need ERB to tell you that #{words.join(' ')}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def not_found(*args)
|
91
|
+
# This one is defined by Monoriel but here we decided to override it
|
92
|
+
# Like :index this method receives the arguments in order to make something with it
|
93
|
+
Email.alert('Many spam emails received') if args.includes?("spam")
|
94
|
+
super(args)
|
95
|
+
end
|
96
|
+
|
97
|
+
def error(err, *args)
|
98
|
+
# Again this one is defined by Monoriel and only shows up when RACK_ENV is not `nil` or `dev` or `development`
|
99
|
+
# Default only prints "ERROR"
|
100
|
+
# Here we're going to send the error message
|
101
|
+
# One would rarely show that to the end user but this is just a demo
|
102
|
+
err.message
|
103
|
+
end
|
104
|
+
|
105
|
+
after do
|
106
|
+
@user.logout
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
- You need to provide the class Page in your models.
|
112
|
+
- You can use slim, haml, scss and erb templates with Monoriel
|
113
|
+
- Please use App in Samples for testing and documentation
|
data/lib/monoriel.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'tilt'
|
3
|
+
|
4
|
+
module Monoriel
|
5
|
+
|
6
|
+
def self.included(klass)
|
7
|
+
klass.class_eval do
|
8
|
+
extend ClassMethods
|
9
|
+
include InstanceMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
attr_reader :before_block, :helpers_block, :after_block
|
15
|
+
def before(&block); @before_block = block; end
|
16
|
+
def helpers(&block); @helpers_block = block; end
|
17
|
+
def after(&block); @after_block = block; end
|
18
|
+
def dispatcher(&block); @dispatcher_block = block; end
|
19
|
+
def dispatcher_block
|
20
|
+
@dispatcher_block || proc{
|
21
|
+
@path_atoms = @r.path_info.split('/').find_all{|s| s!=''}
|
22
|
+
@action, *@action_arguments = @path_atoms
|
23
|
+
@met = @r.request_method == "GET" ? "" : @r.request_method.downcase + "_"
|
24
|
+
@action = @action.gsub("-","_") unless @action.nil?
|
25
|
+
@action = @met + @action unless @action.nil?
|
26
|
+
unless public_methods.include?(@action)||(@action&&public_methods.include?(@action.to_sym))
|
27
|
+
if public_methods.include?('index')||public_methods.include?(:index) # For different RUBY_VERSION(s)
|
28
|
+
@action, @action_arguments = 'index', @path_atoms
|
29
|
+
else
|
30
|
+
@action, @action_arguments = 'not_found', @path_atoms
|
31
|
+
end
|
32
|
+
end
|
33
|
+
instance_eval(&self.class.before_block) unless self.class.before_block.nil?
|
34
|
+
instance_eval(&self.class.helpers_block) unless self.class.helpers_block.nil?
|
35
|
+
begin
|
36
|
+
@res.write(self.__send__(@action,*@action_arguments))
|
37
|
+
rescue ArgumentError => e
|
38
|
+
failed_method = e.backtrace[0][/`.*'$/][1..-2]
|
39
|
+
raise unless failed_method==@action
|
40
|
+
@res.write(self.__send__('not_found', @path_atoms))
|
41
|
+
end
|
42
|
+
instance_eval(&self.class.after_block) unless self.class.after_block.nil?
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module InstanceMethods
|
48
|
+
|
49
|
+
DEV_ENV = [nil,'development','dev']
|
50
|
+
|
51
|
+
def initialize(app=nil); @app = app; end
|
52
|
+
def call(env); dup.call!(env); end
|
53
|
+
|
54
|
+
def call!(env)
|
55
|
+
catch(:response) {
|
56
|
+
@r = ::Rack::Request.new(env)
|
57
|
+
@res = ::Rack::Response.new
|
58
|
+
@session = env['rack.session'] || {}
|
59
|
+
begin
|
60
|
+
instance_eval(&self.class.dispatcher_block)
|
61
|
+
rescue => e
|
62
|
+
raise if DEV_ENV.include?(ENV['RACK_ENV'])
|
63
|
+
@res.write(self.__send__('error', e, @path_atoms))
|
64
|
+
end
|
65
|
+
@res.status==404&&!@app.nil? ? @app.call(env) : @res.finish
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def not_found(*args)
|
70
|
+
@res.status = 404
|
71
|
+
@res.headers['X-Cascade']='pass'
|
72
|
+
"NOT FOUND: #{@r.path_info}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def error(e, *args)
|
76
|
+
puts "\n", e.class, e.message, e.backtrace # Log the error anyway
|
77
|
+
@res.status = 500
|
78
|
+
"ERROR 500"
|
79
|
+
end
|
80
|
+
|
81
|
+
def tpl(template, extention)
|
82
|
+
key = (template.to_s + extention.gsub(/[.]/,"_")).to_sym
|
83
|
+
@@tilt_cache ||= {}
|
84
|
+
if @@tilt_cache.has_key?(key)
|
85
|
+
template_obj = @@tilt_cache[key]
|
86
|
+
else
|
87
|
+
views_location = @r.env['views'] || ::Dir.pwd+'/views/'
|
88
|
+
views_location << '/' unless views_location[-1]==?/
|
89
|
+
template_obj = Tilt.new("#{views_location}#{template}#{extention}")
|
90
|
+
@@tilt_cache.store(key,template_obj) if ENV['RACK_ENV']=='production'
|
91
|
+
end
|
92
|
+
@res['Content-Type'] = "text/html;charset=utf-8"
|
93
|
+
template_obj.render(self)
|
94
|
+
end
|
95
|
+
|
96
|
+
def erb(template)
|
97
|
+
tpl(template,'.erb')
|
98
|
+
end
|
99
|
+
|
100
|
+
def slim(template)
|
101
|
+
tpl(template,'.slim')
|
102
|
+
end
|
103
|
+
|
104
|
+
def haml(template)
|
105
|
+
tpl(template,'.haml')
|
106
|
+
end
|
107
|
+
|
108
|
+
def scss(template)
|
109
|
+
tpl(template,'.scss')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
data/monoriel.gemspec
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'monoriel'
|
3
|
+
s.version = "0.1.1"
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.summary = "A rack based web framework forked from mini-train"
|
6
|
+
s.description = "This is a super simplistic but useful web framework"
|
7
|
+
s.files = `git ls-files`.split("\n").sort
|
8
|
+
s.require_path = './lib'
|
9
|
+
s.author = "Carlos Esquer"
|
10
|
+
s.email = "carlosesquer@zinlim.com"
|
11
|
+
s.homepage = "http://monoriel.zinlim.com"
|
12
|
+
s.add_dependency(%q<tilt>, [">= 1.2.2"])
|
13
|
+
end
|
data/sample/app.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
require '../lib/monoriel'
|
2
|
+
require 'slim'
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class App
|
7
|
+
include Monoriel
|
8
|
+
|
9
|
+
before do
|
10
|
+
# Here you can do many things
|
11
|
+
# In order to help you here are some variables you can read and override:
|
12
|
+
# @r => the Rack::Request object
|
13
|
+
# @res => the Rack::Response object
|
14
|
+
# @action => Name of the public method that will handle the request
|
15
|
+
# @action_arguments => Arguments for the action (really?)
|
16
|
+
end
|
17
|
+
|
18
|
+
helpers do
|
19
|
+
# Altough you can write many things in before block
|
20
|
+
# we recommend you to write helpers here to give your app some structure
|
21
|
+
def simple
|
22
|
+
"<b>Always generate BOLD</b>"
|
23
|
+
end
|
24
|
+
|
25
|
+
def json_response(data=nil)
|
26
|
+
@res['Content-Type'] = "text/plain;charset=utf-8"
|
27
|
+
data.nil? ? "{}" : JSON.generate(data)
|
28
|
+
end
|
29
|
+
|
30
|
+
def yaml_response(data=nil)
|
31
|
+
@res['Content-Type'] = "text/plain;charset=utf-8"
|
32
|
+
data.to_yaml
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def form
|
38
|
+
"<form action='/datos' method='post'>" +
|
39
|
+
"<p> Nombre:" +
|
40
|
+
"<input name='nombre' type='text'> "+
|
41
|
+
"<input type='submit' value='Aceptar'>" +
|
42
|
+
"</p></form>"
|
43
|
+
end
|
44
|
+
|
45
|
+
def update
|
46
|
+
"<form action='/datos' method='post'>" +
|
47
|
+
"<input type='hidden' name='_method' value='put'"+
|
48
|
+
"<p> Nombre:" +
|
49
|
+
"<input name='nombre' type='text' value='Carlitos'>"+
|
50
|
+
"<input type='submit' value='Aceptar'>" +
|
51
|
+
"</p></form>"
|
52
|
+
end
|
53
|
+
|
54
|
+
def post_datos
|
55
|
+
"Si captura los datos -> " + @r.request_method + "<br>" +
|
56
|
+
(@r.put? ? "PUT.." : "POST.." ) + "<br>" +
|
57
|
+
@r.params.class.to_s + "<br>" +
|
58
|
+
@r.params.to_s + "<br>" +
|
59
|
+
@r.POST.to_s + "<br>"
|
60
|
+
end
|
61
|
+
|
62
|
+
def put_datos
|
63
|
+
"Si modifica los datos -> " + @r.request_method + "<br>" +
|
64
|
+
(@r.put? ? "PUT.." : "POST.." ) + "<br>" +
|
65
|
+
@r.params.class.to_s + "<br>" +
|
66
|
+
@r.params.to_s + "<br>" +
|
67
|
+
@r.POST.to_s + "<br>" +
|
68
|
+
@r.params["_method"]
|
69
|
+
end
|
70
|
+
|
71
|
+
def index(*args)
|
72
|
+
# When no public method is found
|
73
|
+
# Of course you don't have to declare one and it is gonna use Controller#not_found instead
|
74
|
+
# Still can have arguments
|
75
|
+
@articles = [{titulo: "hola mundo",contenido: "Este mundo material"},
|
76
|
+
{titulo: "bienvenidos", contenido: "Nunca habra paz..."},
|
77
|
+
{titulo: "el final", contenido: "como en los viejos tiempos"}
|
78
|
+
]
|
79
|
+
simple + (slim :index)
|
80
|
+
#"<h1>Bienvenido</h1><br><h3>Hola mundo...</h3>"
|
81
|
+
end
|
82
|
+
|
83
|
+
def post(id=nil)
|
84
|
+
@post = Post[id]
|
85
|
+
if @post.nil?
|
86
|
+
not_found
|
87
|
+
else
|
88
|
+
erb :post
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def best_restaurants_json
|
93
|
+
# mini-train replaces dots and dashes with underscores
|
94
|
+
# So you can trigger this handler by visiting /best-restaurants.json
|
95
|
+
json_response({
|
96
|
+
'title' => 'Best restaurants in town',
|
97
|
+
'list' => "{ nuevo: 'artículo', antiguo: 'años'}"
|
98
|
+
})
|
99
|
+
end
|
100
|
+
|
101
|
+
def best_restaurants_yaml
|
102
|
+
#you can generate YAML responses (next time we will use XML)
|
103
|
+
yaml_response({
|
104
|
+
'title' => 'Best restaurants in town',
|
105
|
+
'list' => "{ nuevo: 'artículo', antiguo: 'años'}"
|
106
|
+
})
|
107
|
+
end
|
108
|
+
|
109
|
+
def envy(*args)
|
110
|
+
@res['Content-Type'] = "text/html;charset=utf-8"
|
111
|
+
my_res = ""
|
112
|
+
my_res += "<p> Método: #{@r.request_method}</p>"
|
113
|
+
my_res += "<p> Metodo: #{args.to_s}</p>"
|
114
|
+
end
|
115
|
+
|
116
|
+
def say(listener='me', *words)
|
117
|
+
"Hey #{listener} I don't need ERB to tell you that #{words.join(' ')}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def not_found(*args)
|
121
|
+
# This one is defined by mini-train but here we decided to override it
|
122
|
+
# Like :index this method receives the arguments in order to make something with it
|
123
|
+
#Email.alert('Too many people are looking for porn here') if args.includes?("porn")
|
124
|
+
super(args)
|
125
|
+
end
|
126
|
+
|
127
|
+
def error(err, *args)
|
128
|
+
# Again this one is defined by mini-train and only shows up when RACK_ENV is not `nil` or `dev` or `development`
|
129
|
+
# Default only prints "ERROR"
|
130
|
+
# Here we're going to send the error message
|
131
|
+
# One would rarely show that to the end user but this is just a demo
|
132
|
+
err.message
|
133
|
+
end
|
134
|
+
|
135
|
+
after do
|
136
|
+
#Spy.analyse.send_info_to([:government, :facebook, :google, :james_bond])
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
data/sample/config.ru
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
#require 'models' # Loads your models and all ORM stuff
|
2
|
+
require './app' # This is the main file
|
3
|
+
# Some help from other gems
|
4
|
+
use Rack::ContentLength
|
5
|
+
use Rack::Static, urls: ["/css","/js","/html"], root: "public"
|
6
|
+
#use Rack::Session::Cookies
|
7
|
+
run Rack::MethodOverride.new(App.new)
|
@@ -0,0 +1 @@
|
|
1
|
+
alert("hola mundo");
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<head>
|
2
|
+
<link rel='stylesheet' type='text/css' href='http://fonts.googleapis.com/css?family=Play:400,700'/>
|
3
|
+
<link rel="stylesheet" type="text/css" href="/css/layout.css"/>
|
4
|
+
</head>
|
5
|
+
<h1>Algunos artículos (.erb)...<h1>
|
6
|
+
<% @articles.each do |art| %>
|
7
|
+
<h2> <%= art[:titulo] %> </h2>
|
8
|
+
<% end %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
%head
|
2
|
+
%link{:rel=>'stylesheet', :type=>'text/css', :href=>'http://fonts.googleapis.com/css?family=Play:400,700'}
|
3
|
+
%link{:rel=>"stylesheet", :type=>"text/css", :href=>"/css/layout.css"}
|
4
|
+
%body
|
5
|
+
%h1 Algunos artículos (.haml)...
|
6
|
+
%br
|
7
|
+
- @articles.each do |art|
|
8
|
+
%h2= art[:titulo]
|
9
|
+
%br
|
@@ -0,0 +1,11 @@
|
|
1
|
+
head
|
2
|
+
link rel='stylesheet' type='text/css' href='http://fonts.googleapis.com/css?family=Play:400,700'
|
3
|
+
link rel="stylesheet" type="text/css" href="/css/layout.css"
|
4
|
+
body
|
5
|
+
h1 Algunos artículos (.slim)...
|
6
|
+
br
|
7
|
+
- @articles.each do |art|
|
8
|
+
h2= art[:titulo]
|
9
|
+
br
|
10
|
+
.content=art[:contenido]
|
11
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
head
|
2
|
+
link rel='stylesheet' type='text/css' href='http://fonts.googleapis.com/css?family=Play:400,700'
|
3
|
+
link rel="stylesheet" type="text/css" href="/css/layout.css"
|
4
|
+
body
|
5
|
+
h1 Algunos artículos (.slim)...
|
6
|
+
br
|
7
|
+
- @articles.each do |art|
|
8
|
+
h2= art[:titulo]
|
9
|
+
br
|
10
|
+
.content=yield
|
11
|
+
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'rack/lobster'
|
3
|
+
require_relative '../lib/monoriel'
|
4
|
+
|
5
|
+
# =========
|
6
|
+
# = Basic =
|
7
|
+
# =========
|
8
|
+
|
9
|
+
class Basic
|
10
|
+
include Monoriel
|
11
|
+
def no_arg; 'nothing'; end
|
12
|
+
def with_args(a,b); '%s+%s' % [a,b]; end
|
13
|
+
def splat_arg(*a); a.join('+'); end
|
14
|
+
def test_throw
|
15
|
+
throw :response, [200,{'Content-Type'=>'text/html'},['Growl']]
|
16
|
+
'Grrr'
|
17
|
+
end
|
18
|
+
def best_restaurants_rss; '<xml>test</xml>'; end
|
19
|
+
private
|
20
|
+
def no_way; 'This is private'; end
|
21
|
+
end
|
22
|
+
BasicR = ::Rack::MockRequest.new(::Rack::Lint.new(Basic.new))
|
23
|
+
BasicLobsterR = ::Rack::MockRequest.new(::Rack::Lint.new(Basic.new(::Rack::Lobster.new)))
|
24
|
+
|
25
|
+
# ==========
|
26
|
+
# = Filter =
|
27
|
+
# ==========
|
28
|
+
|
29
|
+
class Filter
|
30
|
+
include Monoriel
|
31
|
+
before{@res.write @action=='not_found' ? @action_arguments.join('+') : 'before+'}
|
32
|
+
after{@res.write '+after'}
|
33
|
+
def wrapped; 'wrapped'; end
|
34
|
+
end
|
35
|
+
FilterR = ::Rack::MockRequest.new(::Rack::Lint.new(Filter.new))
|
36
|
+
|
37
|
+
# ===========
|
38
|
+
# = Indexed =
|
39
|
+
# ===========
|
40
|
+
|
41
|
+
class Indexed
|
42
|
+
include Monoriel
|
43
|
+
before{ @res.write("action=#{@action} args=#{@action_arguments.join(',')} ") if @r['switch']=='true' }
|
44
|
+
def index(*a); a.join('+'); end
|
45
|
+
def exist(*a); a.join('+'); end
|
46
|
+
end
|
47
|
+
IndexedR = ::Rack::MockRequest.new(::Rack::Lint.new(Indexed.new))
|
48
|
+
|
49
|
+
# ==================
|
50
|
+
# = Simply indexed =
|
51
|
+
# ==================
|
52
|
+
|
53
|
+
class SimplyIndexed
|
54
|
+
include Monoriel
|
55
|
+
def index; 'index'; end
|
56
|
+
def will_fail; please_fail; end
|
57
|
+
private
|
58
|
+
def please_fail(num); 'ArgumentError baby'; end
|
59
|
+
end
|
60
|
+
SimplyIndexedR = ::Rack::MockRequest.new(::Rack::Lint.new(SimplyIndexed.new))
|
61
|
+
SimplyIndexedUsedR = ::Rack::MockRequest.new(::Rack::Lint.new(SimplyIndexed.new(lambda{|env| [200,{},"#{3+nil}"]})))
|
62
|
+
|
63
|
+
# =============
|
64
|
+
# = Sessioned =
|
65
|
+
# =============
|
66
|
+
|
67
|
+
class Sessioned
|
68
|
+
include Monoriel
|
69
|
+
def set_val(val); @session[:val] = val; end
|
70
|
+
def get_val; @session[:val]; end
|
71
|
+
end
|
72
|
+
SessionedR = ::Rack::MockRequest.new(::Rack::Session::Cookie.new(::Rack::Lint.new(Sessioned.new)))
|
73
|
+
|
74
|
+
# =============
|
75
|
+
# = Helpers =
|
76
|
+
# =============
|
77
|
+
|
78
|
+
class UsingHelpers
|
79
|
+
include Monoriel
|
80
|
+
helpers { def hola(w); "Hola " + w; end }
|
81
|
+
def index; hola("mundo"); end
|
82
|
+
end
|
83
|
+
UsingHelpersR = ::Rack::MockRequest.new(::Rack::Lint.new(UsingHelpers.new))
|
84
|
+
|
85
|
+
# =============
|
86
|
+
# = Post method =
|
87
|
+
# =========
|
88
|
+
|
89
|
+
class UsingPostPutAndDelete
|
90
|
+
include Monoriel
|
91
|
+
#helpers { def params; @r.params; end }
|
92
|
+
def post_data; @r.request_method; end
|
93
|
+
def put_data; @r.request_method; end
|
94
|
+
def delete_data; @r.request_method; end
|
95
|
+
end
|
96
|
+
UsingPostPutAndDeleteR = ::Rack::MockRequest.new(::Rack::Lint.new(Rack::MethodOverride.new(UsingPostPutAndDelete.new)))
|
97
|
+
|
98
|
+
# =========
|
99
|
+
# = Specs =
|
100
|
+
# =========
|
101
|
+
|
102
|
+
describe "Monoriel" do
|
103
|
+
|
104
|
+
it "Should dispatch on a method with no arguments" do
|
105
|
+
assert_equal "nothing",BasicR.get('/no_arg').body
|
106
|
+
end
|
107
|
+
|
108
|
+
it "Should dispatch on a method with arguments" do
|
109
|
+
assert_equal "a+b",BasicR.get('/with_args/a/b').body
|
110
|
+
end
|
111
|
+
|
112
|
+
it "Should dispatch on a method with splat argument" do
|
113
|
+
assert_equal "a+b+c+d",BasicR.get('/splat_arg/a/b/c/d').body
|
114
|
+
end
|
115
|
+
|
116
|
+
it "Should not dispatch if the method is private or does not exist" do
|
117
|
+
r = BasicR.get('/no_way')
|
118
|
+
assert_equal 404,r.status
|
119
|
+
assert_equal "NOT FOUND: /no_way",r.body
|
120
|
+
r = BasicR.get('/no')
|
121
|
+
assert_equal 404,r.status
|
122
|
+
assert_equal "NOT FOUND: /no",r.body
|
123
|
+
end
|
124
|
+
|
125
|
+
it "Should dispatch to appropriate underscored action when name contains '-' or '.'" do
|
126
|
+
assert_equal "<xml>test</xml>",BasicR.get('/best-restaurants-rss').body
|
127
|
+
end
|
128
|
+
|
129
|
+
it "Should only apply '-' and '.' substitution on action names" do
|
130
|
+
assert_equal 'best-restaurants.rss',IndexedR.get('/best-restaurants.rss').body
|
131
|
+
end
|
132
|
+
|
133
|
+
it "Should follow the rack stack if response is 404 and there are middlewares below" do
|
134
|
+
r = BasicLobsterR.get("/no_way")
|
135
|
+
assert_equal 200,r.status
|
136
|
+
end
|
137
|
+
|
138
|
+
it "Should provide filters" do
|
139
|
+
assert_equal "before+wrapped+after",FilterR.get('/wrapped').body
|
140
|
+
end
|
141
|
+
|
142
|
+
it "Should provide arguments in filter when page is not_found" do
|
143
|
+
assert_equal "a+b+c+dNOT FOUND: /a/b/c/d+after",FilterR.get('/a/b/c/d').body
|
144
|
+
end
|
145
|
+
|
146
|
+
it "Should send everything to :index if it exists and there is no matching method for first arg" do
|
147
|
+
assert_equal 'a+b+c+d',IndexedR.get('/exist/a/b/c/d').body
|
148
|
+
assert_equal 'a+b+c+d',IndexedR.get('/a/b/c/d').body
|
149
|
+
assert_equal '',IndexedR.get('/').body
|
150
|
+
end
|
151
|
+
|
152
|
+
it "Should send not_found if there is an argument error on handlers" do
|
153
|
+
assert_equal 200,SimplyIndexedR.get('/').status
|
154
|
+
assert_equal 404,SimplyIndexedR.get('/unknown').status
|
155
|
+
assert_equal 404,SimplyIndexedR.get('/will_fail/useless').status
|
156
|
+
assert_raises(ArgumentError) { SimplyIndexedR.get('/will_fail') }
|
157
|
+
end
|
158
|
+
|
159
|
+
it "Should handle errors without raising an exception unless in dev mode" do
|
160
|
+
assert_raises(ArgumentError) { SimplyIndexedR.get('/will_fail') }
|
161
|
+
ENV['RACK_ENV'] = 'development'
|
162
|
+
assert_raises(ArgumentError) { SimplyIndexedR.get('/will_fail') }
|
163
|
+
ENV['RACK_ENV'] = 'production'
|
164
|
+
@old_stdout = $stdout
|
165
|
+
$stdout = StringIO.new
|
166
|
+
res = SimplyIndexedR.get('/will_fail')
|
167
|
+
logged = $stdout.dup
|
168
|
+
$stdout = @old_stdout
|
169
|
+
assert_equal res.status,500
|
170
|
+
assert_match logged.string, /ArgumentError/
|
171
|
+
ENV['RACK_ENV'] = nil
|
172
|
+
end
|
173
|
+
|
174
|
+
it "Should not use the error handler if the error occurs further down the rack stack" do
|
175
|
+
ENV['RACK_ENV'] = 'production'
|
176
|
+
assert_raises(TypeError) { SimplyIndexedUsedR.get('/not_found') }
|
177
|
+
ENV['RACK_ENV'] = nil
|
178
|
+
end
|
179
|
+
|
180
|
+
it "Should set dispatch-specific variables correctly when defaulting to :index" do
|
181
|
+
assert_equal "action=index args=a,b,c,d a+b+c+d",IndexedR.get('/a/b/c/d?switch=true').body
|
182
|
+
end
|
183
|
+
|
184
|
+
it "Should have a shortcut for session hash" do
|
185
|
+
res = SessionedR.get('/set_val/ichigo')
|
186
|
+
res_2 = SessionedR.get('/get_val', 'HTTP_COOKIE'=>res["Set-Cookie"])
|
187
|
+
assert_equal 'ichigo',res_2.body
|
188
|
+
end
|
189
|
+
|
190
|
+
it "Should catch :response if needed" do
|
191
|
+
assert_equal 'Growl',BasicR.get('/test_throw').body
|
192
|
+
end
|
193
|
+
|
194
|
+
it "Should respond with the helpers content" do
|
195
|
+
assert_equal 'Hola mundo',UsingHelpersR.get('/').body
|
196
|
+
end
|
197
|
+
|
198
|
+
it "Should respond with Post method selector" do
|
199
|
+
assert_equal "POST",UsingPostPutAndDeleteR.post("/data").body
|
200
|
+
assert_equal "PUT",UsingPostPutAndDeleteR.put("/data").body
|
201
|
+
assert_equal "DELETE",UsingPostPutAndDeleteR.delete("/data").body
|
202
|
+
end
|
203
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: monoriel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Carlos Esquer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: tilt
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.2.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.2.2
|
30
|
+
description: This is a super simplistic but useful web framework
|
31
|
+
email: carlosesquer@zinlim.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- README.md
|
37
|
+
- lib/monoriel.rb
|
38
|
+
- monoriel.gemspec
|
39
|
+
- sample/app.rb
|
40
|
+
- sample/config.ru
|
41
|
+
- sample/public/css/layout.css
|
42
|
+
- sample/public/js/common.js
|
43
|
+
- sample/views/index.erb
|
44
|
+
- sample/views/index.haml
|
45
|
+
- sample/views/index.slim
|
46
|
+
- sample/views/index.slim~
|
47
|
+
- test/monoriel-test.rb
|
48
|
+
homepage: http://monoriel.zinlim.com
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- ./lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.24
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: A rack based web framework forked from mini-train
|
72
|
+
test_files: []
|