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.
Files changed (44) hide show
  1. data/History.txt +7 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +43 -0
  4. data/README.txt +48 -0
  5. data/Rakefile +4 -0
  6. data/bin/menta +122 -0
  7. data/config/hoe.rb +70 -0
  8. data/config/requirements.rb +17 -0
  9. data/lib/mentawai/core/action.rb +11 -0
  10. data/lib/mentawai/core/action_config.rb +79 -0
  11. data/lib/mentawai/core/app_context.rb +48 -0
  12. data/lib/mentawai/core/app_manager.rb +111 -0
  13. data/lib/mentawai/core/controller.rb +233 -0
  14. data/lib/mentawai/core/cookies.rb +57 -0
  15. data/lib/mentawai/core/forward.rb +57 -0
  16. data/lib/mentawai/core/input.rb +99 -0
  17. data/lib/mentawai/core/invocation_chain.rb +58 -0
  18. data/lib/mentawai/core/output.rb +51 -0
  19. data/lib/mentawai/core/session.rb +75 -0
  20. data/lib/mentawai/loader.rb +54 -0
  21. data/lib/mentawai/page/methods/out.rb +17 -0
  22. data/lib/mentawai/page/page_method.rb +137 -0
  23. data/lib/mentawai/server.rb +106 -0
  24. data/lib/mentawai/session/menta_session.rb +84 -0
  25. data/lib/mentawai/session/rack_session.rb +91 -0
  26. data/lib/mentawai/util/string.rb +34 -0
  27. data/lib/mentawai/version.rb +9 -0
  28. data/lib/mentawai.rb +16 -0
  29. data/log/debug.log +0 -0
  30. data/script/destroy +14 -0
  31. data/script/generate +14 -0
  32. data/script/txt2html +74 -0
  33. data/setup.rb +1585 -0
  34. data/tasks/deployment.rake +34 -0
  35. data/tasks/environment.rake +7 -0
  36. data/tasks/website.rake +17 -0
  37. data/test/test_helper.rb +2 -0
  38. data/test/test_mentawai.rb +11 -0
  39. data/website/index.html +93 -0
  40. data/website/index.txt +39 -0
  41. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  42. data/website/stylesheets/screen.css +138 -0
  43. data/website/template.rhtml +48 -0
  44. 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
+
@@ -0,0 +1,9 @@
1
+ module Mentawai #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 5
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
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)