mentawai 0.5.0
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/History.txt +7 -0
- data/License.txt +20 -0
- data/Manifest.txt +43 -0
- data/README.txt +48 -0
- data/Rakefile +4 -0
- data/bin/menta +122 -0
- data/config/hoe.rb +70 -0
- data/config/requirements.rb +17 -0
- data/lib/mentawai/core/action.rb +11 -0
- data/lib/mentawai/core/action_config.rb +79 -0
- data/lib/mentawai/core/app_context.rb +48 -0
- data/lib/mentawai/core/app_manager.rb +111 -0
- data/lib/mentawai/core/controller.rb +233 -0
- data/lib/mentawai/core/cookies.rb +57 -0
- data/lib/mentawai/core/forward.rb +57 -0
- data/lib/mentawai/core/input.rb +99 -0
- data/lib/mentawai/core/invocation_chain.rb +58 -0
- data/lib/mentawai/core/output.rb +51 -0
- data/lib/mentawai/core/session.rb +75 -0
- data/lib/mentawai/loader.rb +54 -0
- data/lib/mentawai/page/methods/out.rb +17 -0
- data/lib/mentawai/page/page_method.rb +137 -0
- data/lib/mentawai/server.rb +106 -0
- data/lib/mentawai/session/menta_session.rb +84 -0
- data/lib/mentawai/session/rack_session.rb +91 -0
- data/lib/mentawai/util/string.rb +34 -0
- data/lib/mentawai/version.rb +9 -0
- data/lib/mentawai.rb +16 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/test_helper.rb +2 -0
- data/test/test_mentawai.rb +11 -0
- data/website/index.html +93 -0
- data/website/index.txt +39 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +48 -0
- metadata +102 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
module Mentawai
|
2
|
+
module Page
|
3
|
+
|
4
|
+
class PageMethod
|
5
|
+
|
6
|
+
def initialize(action, parameters)
|
7
|
+
@action = action
|
8
|
+
@params = turn_to_hash(parameters)
|
9
|
+
end
|
10
|
+
|
11
|
+
def params
|
12
|
+
@params
|
13
|
+
end
|
14
|
+
|
15
|
+
alias args params
|
16
|
+
alias param params
|
17
|
+
alias arg params
|
18
|
+
|
19
|
+
def param?(p)
|
20
|
+
@params.key?(p)
|
21
|
+
end
|
22
|
+
|
23
|
+
alias key? param?
|
24
|
+
alias arg? param?
|
25
|
+
alias has_param? param?
|
26
|
+
alias has_key? param?
|
27
|
+
alias has_arg? param?
|
28
|
+
|
29
|
+
def action
|
30
|
+
@action
|
31
|
+
end
|
32
|
+
|
33
|
+
def input
|
34
|
+
@action.input
|
35
|
+
end
|
36
|
+
|
37
|
+
def output
|
38
|
+
@action.output
|
39
|
+
end
|
40
|
+
|
41
|
+
def session
|
42
|
+
@action.session
|
43
|
+
end
|
44
|
+
|
45
|
+
def cookies
|
46
|
+
@action.cookies
|
47
|
+
end
|
48
|
+
|
49
|
+
def application
|
50
|
+
@action.application
|
51
|
+
end
|
52
|
+
|
53
|
+
def locale
|
54
|
+
@action.locale
|
55
|
+
end
|
56
|
+
|
57
|
+
def page
|
58
|
+
@action.page
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
def find_value(name)
|
64
|
+
return nil if @action.nil?
|
65
|
+
|
66
|
+
# Ex: user.address.street
|
67
|
+
parts = name.split(/\./)
|
68
|
+
|
69
|
+
if parts.length > 1 then
|
70
|
+
# The first will be found normally from page, output, etc.
|
71
|
+
first = find_value(parts[0]) # safe recursive call
|
72
|
+
return nil if first.nil?
|
73
|
+
|
74
|
+
# Now find properties of the object found
|
75
|
+
curr_obj = first
|
76
|
+
for index in (1...parts.length) do
|
77
|
+
curr_obj = get_value_by_reflection(curr_obj, parts[index])
|
78
|
+
return nil if curr_obj.nil?
|
79
|
+
end
|
80
|
+
return curr_obj
|
81
|
+
end
|
82
|
+
|
83
|
+
# Rule is simple: page, output, session and application
|
84
|
+
|
85
|
+
return page[name] if page.key?(name)
|
86
|
+
return output[name] if output.key?(name)
|
87
|
+
return session[name] if session.key?(name)
|
88
|
+
return application[name] if application.key?(name)
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def find_form_value(name)
|
93
|
+
return nil if @action.nil?
|
94
|
+
return output[name] if output.key?(name)
|
95
|
+
return input[name] if input.key?(name)
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def get_value_by_reflection(obj, name)
|
102
|
+
# Try getter method
|
103
|
+
if obj.class.public_method_defined?(name) then
|
104
|
+
m = obj.method(name)
|
105
|
+
return m.call if m.arity <= 0
|
106
|
+
end
|
107
|
+
|
108
|
+
# Try instance variable
|
109
|
+
if obj.instance_variable_defined?("@#{name}") then
|
110
|
+
return obj.instance_variable_get("@#{name}")
|
111
|
+
end
|
112
|
+
|
113
|
+
# Try [] method (for hashes and similar objects)
|
114
|
+
if obj.class.public_method_defined?('[]') then
|
115
|
+
m = obj.method('[]')
|
116
|
+
return m.call(name) if m.arity == 1
|
117
|
+
end
|
118
|
+
|
119
|
+
# Not found
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
|
123
|
+
def turn_to_hash(parameters)
|
124
|
+
if parameters.nil? then
|
125
|
+
Hash.new
|
126
|
+
elsif parameters.is_a?(Hash) then
|
127
|
+
parameters
|
128
|
+
else
|
129
|
+
{ :value => parameters.to_s }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'mentawai/loader'
|
3
|
+
require 'mentawai/session/menta_session'
|
4
|
+
|
5
|
+
module Mentawai
|
6
|
+
|
7
|
+
class Server
|
8
|
+
|
9
|
+
attr_accessor :host, :port
|
10
|
+
|
11
|
+
def initialize(path = nil)
|
12
|
+
|
13
|
+
@host = "127.0.0.1"
|
14
|
+
@port = 8080
|
15
|
+
|
16
|
+
@apps = Hash.new
|
17
|
+
|
18
|
+
if not path
|
19
|
+
@loader = nil
|
20
|
+
else
|
21
|
+
@loader = Mentawai::Loader.new(path + '/Mentawai')
|
22
|
+
@loader.reloadFiles
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def application(contextPath, appManagerFilename, appManagerClass)
|
28
|
+
raise "Context already exists: " + contextPath if @apps.has_key?(contextPath)
|
29
|
+
@apps[contextPath] = Application.new(contextPath, appManagerFilename, appManagerClass)
|
30
|
+
end
|
31
|
+
|
32
|
+
def call(env)
|
33
|
+
|
34
|
+
# force reload of any mentawai file if modified...
|
35
|
+
filesLoaded = 0; filesLoaded = @loader.reloadFiles if @loader
|
36
|
+
|
37
|
+
req = Rack::Request.new(env)
|
38
|
+
res = Rack::Response.new(env)
|
39
|
+
|
40
|
+
# Extract context path from URL...
|
41
|
+
if req.fullpath =~ /(\/[^\/]*)/ then
|
42
|
+
contextPath = $1
|
43
|
+
else
|
44
|
+
raise "Cannot get context path: " + env.fullpath
|
45
|
+
end
|
46
|
+
|
47
|
+
# Decide about context path...
|
48
|
+
if @apps.has_key?(contextPath) then
|
49
|
+
# context path was found! (NOOP)
|
50
|
+
elsif @apps.has_key?('/') then
|
51
|
+
contextPath = '/'
|
52
|
+
else
|
53
|
+
raise "Cannot find context: " + contextPath
|
54
|
+
end
|
55
|
+
|
56
|
+
env['menta.contextPath'] = contextPath
|
57
|
+
|
58
|
+
app = @apps[contextPath]
|
59
|
+
app.reloadAppManager(filesLoaded > 0)
|
60
|
+
|
61
|
+
controller = Mentawai::Core::Controller.new(app.contextPath, app.appContext, app.appManager)
|
62
|
+
controller.service(env, req, res)
|
63
|
+
end
|
64
|
+
|
65
|
+
def start
|
66
|
+
|
67
|
+
session_config = { :cookie_expire_after => 0, :session_expire_after => 10 }
|
68
|
+
session_server = Mentawai::Session::MentaSession.new(self, session_config)
|
69
|
+
config = {:Host => @host, :Port => @port}
|
70
|
+
Rack::Handler::Mongrel.run(session_server, config)
|
71
|
+
end
|
72
|
+
|
73
|
+
class Application
|
74
|
+
|
75
|
+
attr_reader :contextPath, :appContext, :appManagerFilename, :appManagerClass, :appManagerFile, :appManager
|
76
|
+
|
77
|
+
def initialize(contextPath, appManagerFilename, appManagerClass)
|
78
|
+
raise "Application manager does not exist: " + appManagerFilename if not File.exists?(appManagerFilename)
|
79
|
+
@appContext = Hash.new
|
80
|
+
@contextPath = contextPath
|
81
|
+
@appManagerFilename = appManagerFilename
|
82
|
+
@appManagerClass = appManagerClass
|
83
|
+
@appManagerFile = File.new(appManagerFilename)
|
84
|
+
@appManagerFileLastModified = 0
|
85
|
+
reloadAppManager
|
86
|
+
end
|
87
|
+
|
88
|
+
def reloadAppManager(force = false)
|
89
|
+
if force || @appManagerFile.mtime != @appManagerFileLastModified then
|
90
|
+
if @appManagerFileLastModified == 0 then
|
91
|
+
puts "Loading app manager: " + @appManagerFilename
|
92
|
+
else
|
93
|
+
puts "Reloading app manager: " + @appManagerFilename
|
94
|
+
end
|
95
|
+
load @appManagerFilename
|
96
|
+
@appManager = eval(appManagerClass + ".new")
|
97
|
+
@appManager.init(@appContext)
|
98
|
+
@appManagerFileLastModified = @appManagerFile.mtime
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'mentawai/session/rack_session'
|
3
|
+
|
4
|
+
module Mentawai
|
5
|
+
module Session
|
6
|
+
|
7
|
+
class MentaSession < RackSession
|
8
|
+
|
9
|
+
def initialize(app, options = {}) # in minutes
|
10
|
+
|
11
|
+
# Rename expire_after to cooki_expire_after for clarity...
|
12
|
+
if options.key?(:cookie_expire_after) then
|
13
|
+
options[:expire_after] = options[:cookie_expire_after]
|
14
|
+
end
|
15
|
+
|
16
|
+
timeout = 10 # default
|
17
|
+
timeout = options[:session_expire_after] if options.key?(:session_expire_after)
|
18
|
+
|
19
|
+
@timeout = (timeout * 60).to_i # now in seconds (allow float timeout)
|
20
|
+
@lastcheck = Time.now
|
21
|
+
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
# Convenient method to get session_id from cookie
|
26
|
+
def get_session_id(env)
|
27
|
+
env.fetch('HTTP_COOKIE','')[/#{@key}=([^,;]+)/,1] # copied from Rack code
|
28
|
+
end
|
29
|
+
|
30
|
+
# Override loadSession to purge expired sessions...
|
31
|
+
|
32
|
+
def load_session(env)
|
33
|
+
|
34
|
+
now = Time.now
|
35
|
+
|
36
|
+
@lock.synchronize {
|
37
|
+
|
38
|
+
# Check if session was invalidated...
|
39
|
+
session_id = get_session_id(env)
|
40
|
+
if session_id && pool.key?(session_id) then
|
41
|
+
|
42
|
+
s = pool[session_id]
|
43
|
+
sdat = s.instance_variable_get '@dat'
|
44
|
+
|
45
|
+
raise "Something is wrong!" unless sdat[0] == session_id # sanity...
|
46
|
+
|
47
|
+
lastaccess = sdat[1]
|
48
|
+
|
49
|
+
if lastaccess == 0 || now - lastaccess > @timeout then
|
50
|
+
pool.delete(session_id)
|
51
|
+
|
52
|
+
s.each do |k,v|
|
53
|
+
v.removed_from_session(k) if v.respond_to?(:removed_from_session)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
if now - @lastcheck >= @timeout then
|
61
|
+
# now purge all expired sessions...
|
62
|
+
pool.each do |id,session|
|
63
|
+
sdat = session.instance_variable_get '@dat'
|
64
|
+
lastaccess = sdat[1]
|
65
|
+
if lastaccess == 0 || now - lastaccess > @timeout then
|
66
|
+
pool.delete(id)
|
67
|
+
session.each do |k,v|
|
68
|
+
v.removed_from_session(k) if v.respond_to?(:removed_from_session)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
@lastcheck = now
|
73
|
+
end
|
74
|
+
|
75
|
+
}
|
76
|
+
|
77
|
+
super # do what you have to do...
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
|
2
|
+
# Modified by Sergio Oliveira to synchronize the pool of sessions...
|
3
|
+
|
4
|
+
require 'thread'
|
5
|
+
|
6
|
+
module Mentawai
|
7
|
+
module Session
|
8
|
+
# Rack::Session::Pool provides simple cookie based session management.
|
9
|
+
# Session data is stored in a hash held by @pool. The corresponding
|
10
|
+
# session key sent to the client.
|
11
|
+
# The pool is unmonitored and unregulated, which means that over
|
12
|
+
# prolonged use the session pool will be very large.
|
13
|
+
#
|
14
|
+
# Example:
|
15
|
+
#
|
16
|
+
# use Rack::Session::Pool, :key => 'rack.session',
|
17
|
+
# :domain => 'foo.com',
|
18
|
+
# :path => '/',
|
19
|
+
# :expire_after => 2592000
|
20
|
+
#
|
21
|
+
# All parameters are optional.
|
22
|
+
|
23
|
+
class RackSession
|
24
|
+
|
25
|
+
attr_reader :pool, :key
|
26
|
+
|
27
|
+
def initialize(app, options={})
|
28
|
+
@app = app
|
29
|
+
@key = options[:key] || "rack.session"
|
30
|
+
@default_options = {:domain => nil,
|
31
|
+
:path => "/",
|
32
|
+
:expire_after => nil}.merge(options)
|
33
|
+
@pool = Hash.new
|
34
|
+
@default_context = context app, &nil
|
35
|
+
@lock = Mutex.new
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def call(env)
|
40
|
+
@default_context.call(env)
|
41
|
+
end
|
42
|
+
|
43
|
+
def context(app, &block)
|
44
|
+
Rack::Utils::Context.new self, app do |env|
|
45
|
+
load_session env
|
46
|
+
block[env] if block
|
47
|
+
response = app.call(env)
|
48
|
+
commit_session env, response
|
49
|
+
response
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def load_session(env)
|
56
|
+
|
57
|
+
sess_id = env.fetch('HTTP_COOKIE','')[/#{@key}=([^,;]+)/,1]
|
58
|
+
|
59
|
+
@lock.synchronize {
|
60
|
+
begin
|
61
|
+
sess_id = Array.new(8){rand(16).to_s(16)}*''
|
62
|
+
end while @pool.key? sess_id if sess_id.nil? or !@pool.key? sess_id
|
63
|
+
|
64
|
+
session = @pool.fetch sess_id, {}
|
65
|
+
@pool.store sess_id, env['rack.session'] = session
|
66
|
+
session.instance_variable_set '@dat', [sess_id, Time.now]
|
67
|
+
}
|
68
|
+
|
69
|
+
env["rack.session.options"] = @default_options.dup
|
70
|
+
end
|
71
|
+
|
72
|
+
def commit_session(env, response)
|
73
|
+
session = env['rack.session']
|
74
|
+
options = env['rack.session.options']
|
75
|
+
sdat = session.instance_variable_get '@dat'
|
76
|
+
|
77
|
+
cookie = Rack::Utils.escape(@key)+'='+ Rack::Utils.escape(sdat[0])
|
78
|
+
cookie<< "; domain=#{options[:domain]}" if options[:domain]
|
79
|
+
cookie<< "; path=#{options[:path]}" if options[:path]
|
80
|
+
cookie<< "; expires=#{sdat[1]+options[:expires_after]}" if options[:expires_after]
|
81
|
+
|
82
|
+
case a = (h = response[1])['Set-Cookie']
|
83
|
+
when Array then a << cookie
|
84
|
+
when String then h['Set-Cookie'] = [a, cookie]
|
85
|
+
when nil then h['Set-Cookie'] = cookie
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
class String
|
3
|
+
|
4
|
+
alias each_byte_orig each_byte
|
5
|
+
alias lindex index
|
6
|
+
|
7
|
+
def each_byte
|
8
|
+
index = 0
|
9
|
+
each_byte_orig do |b|
|
10
|
+
yield b, index
|
11
|
+
index += 1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def each_char
|
16
|
+
index = 0
|
17
|
+
each_byte_orig do |b|
|
18
|
+
yield b.chr, index
|
19
|
+
index += 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def String.testMe
|
24
|
+
"aaa".each_byte { |b,n| print "Byte: #{b} (#{n})\n" }
|
25
|
+
"aaa".each_char { |c,n| print "Char: #{c} (#{n})\n" }
|
26
|
+
print "Index: ","aaabbbccc".lindex('ab'),"\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
String.testMe if ARGV[0] == "testMe"
|
32
|
+
|
33
|
+
|
34
|
+
|
data/lib/mentawai.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Require all mentawai files here...
|
2
|
+
|
3
|
+
root = File.expand_path(File.dirname(__FILE__))
|
4
|
+
|
5
|
+
# Load two lonely files in mentawai/
|
6
|
+
|
7
|
+
require root + '/mentawai/loader'
|
8
|
+
require root + '/mentawai/server'
|
9
|
+
|
10
|
+
# Now loop and load everything inside '/mentawai/**'
|
11
|
+
|
12
|
+
path = root + '/mentawai/**/*.rb'
|
13
|
+
|
14
|
+
Dir.glob(path).each do |file|
|
15
|
+
require file
|
16
|
+
end
|
data/log/debug.log
ADDED
File without changes
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/script/txt2html
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
begin
|
5
|
+
require 'newgem'
|
6
|
+
rescue LoadError
|
7
|
+
puts "\n\nGenerating the website requires the newgem RubyGem"
|
8
|
+
puts "Install: gem install newgem\n\n"
|
9
|
+
exit(1)
|
10
|
+
end
|
11
|
+
require 'redcloth'
|
12
|
+
require 'syntax/convertors/html'
|
13
|
+
require 'erb'
|
14
|
+
require File.dirname(__FILE__) + '/../lib/mentawai/version.rb'
|
15
|
+
|
16
|
+
version = Mentawai::VERSION::STRING
|
17
|
+
download = 'http://rubyforge.org/projects/mentawai'
|
18
|
+
|
19
|
+
class Fixnum
|
20
|
+
def ordinal
|
21
|
+
# teens
|
22
|
+
return 'th' if (10..19).include?(self % 100)
|
23
|
+
# others
|
24
|
+
case self % 10
|
25
|
+
when 1: return 'st'
|
26
|
+
when 2: return 'nd'
|
27
|
+
when 3: return 'rd'
|
28
|
+
else return 'th'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Time
|
34
|
+
def pretty
|
35
|
+
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def convert_syntax(syntax, source)
|
40
|
+
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
|
41
|
+
end
|
42
|
+
|
43
|
+
if ARGV.length >= 1
|
44
|
+
src, template = ARGV
|
45
|
+
template ||= File.join(File.dirname(__FILE__), '/../website/template.rhtml')
|
46
|
+
|
47
|
+
else
|
48
|
+
puts("Usage: #{File.split($0).last} source.txt [template.rhtml] > output.html")
|
49
|
+
exit!
|
50
|
+
end
|
51
|
+
|
52
|
+
template = ERB.new(File.open(template).read)
|
53
|
+
|
54
|
+
title = nil
|
55
|
+
body = nil
|
56
|
+
File.open(src) do |fsrc|
|
57
|
+
title_text = fsrc.readline
|
58
|
+
body_text = fsrc.read
|
59
|
+
syntax_items = []
|
60
|
+
body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
|
61
|
+
ident = syntax_items.length
|
62
|
+
element, syntax, source = $1, $2, $3
|
63
|
+
syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
|
64
|
+
"syntax-temp-#{ident}"
|
65
|
+
}
|
66
|
+
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
|
67
|
+
body = RedCloth.new(body_text).to_html
|
68
|
+
body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
|
69
|
+
end
|
70
|
+
stat = File.stat(src)
|
71
|
+
created = stat.ctime
|
72
|
+
modified = stat.mtime
|
73
|
+
|
74
|
+
$stdout << template.result(binding)
|