ruil 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/README.rdoc +40 -0
- data/VERSION +1 -0
- data/lib/ruil/delegator.rb +42 -0
- data/lib/ruil/resource.rb +84 -0
- data/lib/ruil/tenjin_template.rb +20 -0
- data/rakefile +53 -0
- data/test/delegator_test.rb +50 -0
- data/test/resource_test.rb +23 -0
- data/test/templates/a.desktop.html +1 -0
- data/test/templates/a.mobile.html +1 -0
- data/test/templates/b.desktop.html +1 -0
- data/test/templates/b.mobile.html +1 -0
- metadata +78 -0
data/README.rdoc
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
= ruil
|
2
|
+
|
3
|
+
Basic tools for build web appplications on top of rack
|
4
|
+
|
5
|
+
== Install
|
6
|
+
|
7
|
+
$ gem install ruil
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
=== Code example
|
12
|
+
|
13
|
+
== Install from code
|
14
|
+
|
15
|
+
First download the code from the repository:
|
16
|
+
|
17
|
+
$ git clone git@github.com:danielhz/ruil.git
|
18
|
+
|
19
|
+
This project uses jeweler to build the gem, so you can use this commands:
|
20
|
+
|
21
|
+
$ rake build # to build the gem
|
22
|
+
$ rake install # to build and install the gem in one step
|
23
|
+
|
24
|
+
Also, if you want test the gem you can use the spec task:
|
25
|
+
|
26
|
+
$ rake spec
|
27
|
+
|
28
|
+
This project uses rcov so you can check the coverage opening the HTML
|
29
|
+
file in the coverage directory after running the spec.
|
30
|
+
|
31
|
+
== Other Stuff
|
32
|
+
|
33
|
+
Author:: Daniel Hernández, daniel@degu.cl
|
34
|
+
License:: GPL V3
|
35
|
+
|
36
|
+
== Warranty
|
37
|
+
|
38
|
+
This software is provided "as is" and without any express or implied
|
39
|
+
warranties, including, without limitation, the implied warranties of
|
40
|
+
merchantability and fitness for a particular purpose.
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
module Ruil
|
4
|
+
|
5
|
+
class Delegator
|
6
|
+
|
7
|
+
# Initialize a delegator
|
8
|
+
def initialize(user_agent_parser, template_dir, template_engine, &block)
|
9
|
+
@user_agent_parser = user_agent_parser
|
10
|
+
@template_engine = template_engine
|
11
|
+
@template_dir = template_dir
|
12
|
+
@resources = []
|
13
|
+
yield self
|
14
|
+
end
|
15
|
+
|
16
|
+
# Default action
|
17
|
+
def default(env)
|
18
|
+
[ 302, {"Content-Type" => "text/html", 'Location'=> '/' }, [] ]
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_resource(resource_class)
|
22
|
+
resource_class.new(@user_agent_parser) do |r|
|
23
|
+
Dir[File.join(@template_dir, r.template_pattern)].each do |file|
|
24
|
+
user_agent = File.basename(file).split('.')[1]
|
25
|
+
template = @template_engine.new(file)
|
26
|
+
r.add_template user_agent.to_sym, template
|
27
|
+
end
|
28
|
+
@resources << [r.path_pattern, r]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Call method
|
33
|
+
def call(env)
|
34
|
+
@resources.each do |path_pattern, proc|
|
35
|
+
return proc.call(env) if path_pattern === env['PATH_INFO']
|
36
|
+
end
|
37
|
+
default(env)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
module Ruil
|
4
|
+
|
5
|
+
class Resource
|
6
|
+
|
7
|
+
# Initialize a new resource.
|
8
|
+
#
|
9
|
+
# Parameters:
|
10
|
+
# - templates: a hash with procedures or objects with method call(options),
|
11
|
+
# used to generate the resource.
|
12
|
+
# - user_agent_parser: is an object with a method call that analize the
|
13
|
+
# request to get the key for the template to use.
|
14
|
+
def initialize(user_agent_parser, &block)
|
15
|
+
@templates = {}
|
16
|
+
@user_agent_parser = user_agent_parser
|
17
|
+
yield self
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_template(key, template)
|
21
|
+
@templates[key] = template
|
22
|
+
end
|
23
|
+
|
24
|
+
# The regular expression for the url of this resource.
|
25
|
+
def path_pattern
|
26
|
+
'/'
|
27
|
+
end
|
28
|
+
|
29
|
+
# The regular expression for the url of this resource.
|
30
|
+
def template_pattern
|
31
|
+
'*.*.html'
|
32
|
+
end
|
33
|
+
|
34
|
+
# Authorize the access to this resource.
|
35
|
+
def authorize(env)
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
# Build options to render the resource.
|
40
|
+
def options(env)
|
41
|
+
{
|
42
|
+
:env => env,
|
43
|
+
:template_key => template_key(env)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Selects the template key
|
48
|
+
def template_key(env)
|
49
|
+
@user_agent_parser.call(env) || @templates.keys.sort.first
|
50
|
+
end
|
51
|
+
|
52
|
+
# Selectes a template to render the resource
|
53
|
+
def template(env)
|
54
|
+
@templates[template_key(env)]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Call the resource
|
58
|
+
def call(env)
|
59
|
+
if authorize(env)
|
60
|
+
render_html(env)
|
61
|
+
else
|
62
|
+
unauthorized(env)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Action if the resource is unauthorized
|
67
|
+
def unauthorized(env)
|
68
|
+
redirect("/unauthorized")
|
69
|
+
end
|
70
|
+
|
71
|
+
# Render
|
72
|
+
def render_html(env)
|
73
|
+
content = template(env).call(options(env))
|
74
|
+
[200, {"Content-Type" => "text/html"}, [content]]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Redirect
|
78
|
+
def redirect(url)
|
79
|
+
[ 302, {"Content-Type" => "text/html", 'Location'=> url }, [] ]
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'tenjin'
|
3
|
+
|
4
|
+
module Ruil
|
5
|
+
|
6
|
+
class TenjinTemplate
|
7
|
+
|
8
|
+
@@engine = Tenjin::Engine.new
|
9
|
+
|
10
|
+
def initialize(file)
|
11
|
+
@file = file
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(options)
|
15
|
+
@@engine.render(@file, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
desc 'Default: run rspec tests.'
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
desc 'Run all tests'
|
10
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
11
|
+
t.spec_files = Dir.glob('test/*_test.rb')
|
12
|
+
t.spec_opts << '--format specdoc'
|
13
|
+
t.rcov = true
|
14
|
+
end
|
15
|
+
|
16
|
+
begin
|
17
|
+
require 'jeweler'
|
18
|
+
Jeweler::Tasks.new do |gemspec|
|
19
|
+
gemspec.name = "ruil"
|
20
|
+
gemspec.authors = ["Daniel Hernández"]
|
21
|
+
gemspec.email = "daniel@degu.cl"
|
22
|
+
gemspec.homepage = "http://github.com/danielhz/ruil"
|
23
|
+
gemspec.summary = "Basic tools for build web appplications on top of rack"
|
24
|
+
gemspec.rubyforge_project = "ruil"
|
25
|
+
gemspec.description = "It provides a class to derivate the application resources\n" +
|
26
|
+
"and a delegator that select the appropiate resource to answer\n" +
|
27
|
+
"a request. Also, it include a templating adapter based on Tenjin."
|
28
|
+
end
|
29
|
+
rescue LoadError
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
require 'darkfish-rdoc'
|
34
|
+
DARKFISH_ENABLED = true
|
35
|
+
rescue LoadError => ex
|
36
|
+
DARKFISH_ENABLED = false
|
37
|
+
end
|
38
|
+
|
39
|
+
BASE_RDOC_OPTIONS = [
|
40
|
+
'--line-numbers', '--inline-source',
|
41
|
+
'--main' , 'README.rdoc',
|
42
|
+
'--title', 'uagent'
|
43
|
+
]
|
44
|
+
|
45
|
+
rd = Rake::RDocTask.new do |rdoc|
|
46
|
+
rdoc.rdoc_dir = 'html'
|
47
|
+
rdoc.title = "ruil"
|
48
|
+
rdoc.options = BASE_RDOC_OPTIONS.dup
|
49
|
+
rdoc.options << '-SHN' << '-f' << 'darkfish' if DARKFISH_ENABLED
|
50
|
+
rdoc.options << '--charset' << 'utf-8'
|
51
|
+
rdoc.rdoc_files.include('README.rdoc')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc')
|
53
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ruil/delegator'
|
3
|
+
require 'ruil/resource'
|
4
|
+
require 'ruil/tenjin_template'
|
5
|
+
|
6
|
+
describe 'Delegator' do
|
7
|
+
|
8
|
+
before(:all) do
|
9
|
+
a_resource = Class.new(Ruil::Resource) do
|
10
|
+
def path_pattern
|
11
|
+
/^\/a/
|
12
|
+
end
|
13
|
+
def template_pattern
|
14
|
+
'a.*.html'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
b_resource = Class.new(Ruil::Resource) do
|
18
|
+
def path_pattern
|
19
|
+
/^\/b/
|
20
|
+
end
|
21
|
+
def template_pattern
|
22
|
+
'b.*.html'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
user_agent_parser = Proc.new do |env|
|
26
|
+
/Mobile/ === env['HTTP_USER_AGENT'] ? :mobile : :desktop
|
27
|
+
end
|
28
|
+
template_dir = File.join(File.dirname(__FILE__), 'templates')
|
29
|
+
@delegator = Ruil::Delegator.new(user_agent_parser, template_dir, Ruil::TenjinTemplate) do |d|
|
30
|
+
d.add_resource a_resource
|
31
|
+
d.add_resource b_resource
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'delegate a request' do
|
36
|
+
env = { 'PATH_INFO' => '/a', 'HTTP_USER_AGENT' => 'Mobile' }
|
37
|
+
exp = [200, {"Content-Type" => "text/html"}, ["a mobile\n"]]
|
38
|
+
@delegator.call(env).should == exp
|
39
|
+
env = { 'PATH_INFO' => '/a', 'HTTP_USER_AGENT' => 'Desktop' }
|
40
|
+
exp = [200, {"Content-Type" => "text/html"}, ["a desktop\n"]]
|
41
|
+
@delegator.call(env).should == exp
|
42
|
+
env = { 'PATH_INFO' => '/b', 'HTTP_USER_AGENT' => 'Desktop' }
|
43
|
+
exp = [200, {"Content-Type" => "text/html"}, ["b desktop\n"]]
|
44
|
+
@delegator.call(env).should == exp
|
45
|
+
env = { 'PATH_INFO' => '/c', 'HTTP_USER_AGENT' => 'Desktop' }
|
46
|
+
exp =[ 302, {"Content-Type" => "text/html", 'Location'=> '/' }, [] ]
|
47
|
+
@delegator.call(env).should == exp
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ruil/resource'
|
3
|
+
|
4
|
+
describe 'Resource' do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
user_agent_parser = Proc.new do |env|
|
8
|
+
/Mobile/ === env['HTTP_USER_AGENT'] ? :mobile : :desktop
|
9
|
+
end
|
10
|
+
@resource = Ruil::Resource.new(user_agent_parser) do |r|
|
11
|
+
r.add_template :mobile, Proc.new { |opt| opt[:template_key].to_s }
|
12
|
+
r.add_template :desktop, Proc.new { |opt| opt[:template_key].to_s }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should display a content' do
|
17
|
+
env = { 'HTTP_USER_AGENT' => 'Mobile' }
|
18
|
+
@resource.call(env).should == [200, {"Content-Type" => "text/html"}, ['mobile']]
|
19
|
+
env = { 'HTTP_USER_AGENT' => 'Desktop' }
|
20
|
+
@resource.call(env).should == [200, {"Content-Type" => "text/html"}, ['desktop']]
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
a #{@template_key}
|
@@ -0,0 +1 @@
|
|
1
|
+
a #{@template_key}
|
@@ -0,0 +1 @@
|
|
1
|
+
b #{@template_key}
|
@@ -0,0 +1 @@
|
|
1
|
+
b #{@template_key}
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruil
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- "Daniel Hern\xC3\xA1ndez"
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-09-26 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: |-
|
22
|
+
It provides a class to derivate the application resources
|
23
|
+
and a delegator that select the appropiate resource to answer
|
24
|
+
a request. Also, it include a templating adapter based on Tenjin.
|
25
|
+
email: daniel@degu.cl
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README.rdoc
|
32
|
+
files:
|
33
|
+
- .gitignore
|
34
|
+
- README.rdoc
|
35
|
+
- VERSION
|
36
|
+
- lib/ruil/delegator.rb
|
37
|
+
- lib/ruil/resource.rb
|
38
|
+
- lib/ruil/tenjin_template.rb
|
39
|
+
- rakefile
|
40
|
+
- test/delegator_test.rb
|
41
|
+
- test/resource_test.rb
|
42
|
+
- test/templates/a.desktop.html
|
43
|
+
- test/templates/a.mobile.html
|
44
|
+
- test/templates/b.desktop.html
|
45
|
+
- test/templates/b.mobile.html
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/danielhz/ruil
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options:
|
52
|
+
- --charset=UTF-8
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project: ruil
|
72
|
+
rubygems_version: 1.3.6
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Basic tools for build web appplications on top of rack
|
76
|
+
test_files:
|
77
|
+
- test/resource_test.rb
|
78
|
+
- test/delegator_test.rb
|