ruil 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.
- 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
|