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,233 @@
1
+ require 'monitor'
2
+
3
+ module Mentawai
4
+ module Core
5
+
6
+ class Controller
7
+
8
+ @@forward_cache = Hash.new
9
+ @@forward_cache.extend(MonitorMixin)
10
+
11
+ def initialize(contextPath, appContext, appManager)
12
+ @contextPath = contextPath
13
+ @appContext = appContext
14
+ @appManager = appManager
15
+ end
16
+
17
+ attr_reader :appManager, :action, :contextPath
18
+
19
+ def output
20
+ @action.output
21
+ end
22
+
23
+ def application
24
+ @action.application
25
+ end
26
+
27
+ def input
28
+ @action.input
29
+ end
30
+
31
+ def session
32
+ @action.session
33
+ end
34
+
35
+ def locale
36
+ @action.locale
37
+ end
38
+
39
+ def cookies
40
+ @action.cookies
41
+ end
42
+
43
+ def page
44
+ @action.page
45
+ end
46
+
47
+ def service(env, req, res)
48
+
49
+ url = req.fullpath.dup
50
+
51
+ # Check if we are directly acessing a
52
+ # static page instead of an action
53
+ if url =~ /\.(\w{1,4})$/ then
54
+ if Forward.types.key?($1) then
55
+ return service_direct(env, req, res)
56
+ end
57
+ end
58
+
59
+ fix_url(url)
60
+
61
+ url.gsub!(/\.\w{1,4}$/, "") # remote any extension (max 4 chars)
62
+
63
+ actionName = nil
64
+ innerAction = nil
65
+
66
+ if (index = url.rindex('.')) != nil then
67
+ actionName = url[0, index]
68
+ innerAction = url[index + 1, url.length]
69
+ else
70
+ actionName = url
71
+ end
72
+
73
+ @appManager.reloadActions
74
+
75
+ ac = @appManager.getActionConfig(actionName, innerAction)
76
+
77
+ if ac then
78
+ @action = eval("#{ac.className}.new")
79
+ else
80
+ # If you cannot find action config then use conventions...
81
+ @action = eval("#{actionName}.new")
82
+ end
83
+
84
+ prepare(@action, req, res)
85
+
86
+ chain = InvocationChain.new(@action, actionName, innerAction)
87
+
88
+ @appManager.filters { |f| chain.addFilter(f) }
89
+
90
+ ac.filters { |f| chain.addFilter(f) } if ac
91
+
92
+ result = chain.invoke
93
+
94
+ conseq = nil
95
+
96
+ conseq = ac.getConsequence(result) if ac
97
+
98
+ conseq = @appManager.getConsequence(result) if not conseq
99
+
100
+ if not conseq then
101
+
102
+ # Use conventions to find a view
103
+ dest = actionName + "/" + (innerAction ? innerAction : 'index') + '.erb'
104
+
105
+ # Cache forward consequence...
106
+ @@forward_cache.synchronize {
107
+ conseq = @@forward_cache[dest]
108
+ if not conseq then
109
+ # Check if file exists
110
+ if File.exists?("./views/" + dest) then
111
+ @@forward_cache[dest] = conseq = Forward.new(dest)
112
+ end
113
+ end
114
+ }
115
+ end
116
+
117
+ raise "Cannot find consequence! action=#{actionName} inner=#{innerAction ? innerAction : 'nil'}" if not conseq
118
+
119
+ conseq.exec(self, req, res, @action)
120
+
121
+ end
122
+
123
+ def service_direct(env, req, res)
124
+
125
+ # Accessing a page file directly
126
+
127
+ url = req.fullpath.dup
128
+
129
+ fix_url(url)
130
+
131
+ @action = Mentawai::Core::Action.new
132
+
133
+ prepare(@action, req, res)
134
+
135
+ forward = nil
136
+
137
+ # Cache forward consequence...
138
+ @@forward_cache.synchronize {
139
+ forward = @@forward_cache[url]
140
+ @@forward_cache[url] = forward = Forward.new(url) if not forward
141
+ }
142
+
143
+ forward.exec(self, req, res, @action)
144
+
145
+ end
146
+
147
+ protected
148
+
149
+ def fix_url(url)
150
+ url.gsub!(/^#{@contextPath}/, "") # remove context path
151
+ url.gsub!(/\?.*$/, "") # remove query string (if present)
152
+ url.gsub!(/^\//, "") # remove a '/' from begining
153
+ url.gsub!(/\/$/, "") # remove a '/' from ending
154
+ end
155
+
156
+ def prepare(action, request, response)
157
+ i = Input.new(request)
158
+ o = Output.new(response)
159
+ s = Session.new(request, response)
160
+ c = Cookies.new(request, response)
161
+
162
+ if action.is_a?(Action) then
163
+ action.input = i
164
+ action.output = o
165
+ action.session = s
166
+ action.cookies = c
167
+ action.application = @appContext
168
+ action.page = Hash.new
169
+ else
170
+ raise "Not an action: " + action.to_s
171
+ end
172
+ end
173
+ end
174
+
175
+ private
176
+
177
+ def exec_page_method(className, methodName, args)
178
+ if args.length <= 0 then
179
+ m = eval(className + ".new(self, nil)")
180
+ else
181
+ m = eval(className + ".new(self, args[0])")
182
+ end
183
+ m.send(methodName)
184
+ end
185
+
186
+ def method_missing(id, *args)
187
+
188
+ # Crazy bug: method_missing is being called for everything
189
+ # and not just for controller. Make a crazy call inside
190
+ # an action an you will see;
191
+ #
192
+ # Ex:
193
+ # class MyAction < Mentawai::Core::Action
194
+ # def execute
195
+ # a = {}
196
+ # a.blow
197
+ # end
198
+ # end
199
+ #
200
+ # The action above will trigger method_missing from
201
+ # the controller! Now you tell me why!!!
202
+ if not self.is_a?(Controller)
203
+ # This method missing is from the Controller only!
204
+ # I don't want actions triggering this guys!
205
+ # You tell me why this is happening since I have already
206
+ # tried everything to understand this...
207
+ super
208
+ end
209
+
210
+ # First look custom page methods
211
+ if args.length <= 1 && @appManager.customPageMethods.key?(id) then
212
+
213
+ className = @appManager.customPageMethods[id][0]
214
+ methodName = @appManager.customPageMethods[id][1]
215
+ exec_page_method(className, methodName, args)
216
+
217
+ # Then look menta page methods
218
+ elsif args.length <= 1 && @appManager.pageMethods.key?(id) then
219
+
220
+ className = @appManager.pageMethods[id][0]
221
+ methodName = @appManager.pageMethods[id][1]
222
+ exec_page_method(className, methodName, args)
223
+
224
+ else
225
+ super
226
+ end
227
+ end
228
+
229
+ end
230
+ end
231
+
232
+
233
+
@@ -0,0 +1,57 @@
1
+ module Mentawai
2
+ module Core
3
+
4
+ class Cookies
5
+
6
+ attr_reader :request, :response
7
+
8
+ def initialize(request, response)
9
+ @req = request
10
+ @res = response
11
+ @cookies = request.cookies
12
+ end
13
+
14
+ def put(key, value)
15
+ @res.set_cookie(key, value)
16
+ end
17
+
18
+ def get(key)
19
+ @cookies[key]
20
+ end
21
+
22
+ def remove(key)
23
+ @res.delete_cookie(key)
24
+ end
25
+
26
+ def hasKey?(key)
27
+ @cookies.has_key?(key)
28
+ end
29
+
30
+ alias has_key? hasKey?
31
+ alias key? hasKey?
32
+
33
+ def keys
34
+ @cookies.each do |k,v|
35
+ yield k
36
+ end
37
+ end
38
+
39
+ def values
40
+ @cookies.each do |k,v|
41
+ yield k,v
42
+ end
43
+ end
44
+
45
+ alias each values
46
+ alias [] get
47
+ alias []= put
48
+ alias delete remove
49
+
50
+ end
51
+
52
+ end
53
+ end
54
+
55
+
56
+
57
+
@@ -0,0 +1,57 @@
1
+ require 'erubis'
2
+ require 'thread'
3
+
4
+ module Mentawai
5
+ module Core
6
+
7
+ class Forward
8
+
9
+ DEFAULT_TYPE = 'text/html'
10
+
11
+ @@types = Hash.new
12
+ @@types['erb'] = 'text/html'
13
+ @@types['txt'] = 'text/plain'
14
+ @@types['xml'] = 'text/xml'
15
+
16
+ def self.types
17
+ @@types
18
+ end
19
+
20
+ def initialize(page)
21
+ @page = page
22
+ if page =~ /\.(\w+)$/ then
23
+ @contentType = @@types[$1] || DEFAULT_TYPE
24
+ else
25
+ @contentType = DEFAULT_TYPE
26
+ end
27
+ @filename = './views/' + page
28
+ raise "Cannot find page: " + page if not File.exists?(@filename)
29
+ @file = File.new(@filename)
30
+ @lastmodified = @file.mtime
31
+ input = File.read(@filename)
32
+ @eruby = Erubis::Eruby.new(input)
33
+ @lock = Mutex.new
34
+ end
35
+
36
+ def exec(controller, req, res, action)
37
+ @lock.synchronize {
38
+ if @lastmodified != @file.mtime then
39
+ input = File.read(@filename)
40
+ @eruby = Erubis::Eruby.new(input)
41
+ @lastmodified = @file.mtime
42
+ puts "Reloading #{@page}"
43
+ end
44
+ }
45
+ data = @eruby.result(controller.send(:binding))
46
+
47
+ res['Content-Type'] = @contentType
48
+ res.status = 200 # OK
49
+ res.body = data
50
+
51
+ res.finish
52
+
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,99 @@
1
+ module Mentawai
2
+ module Core
3
+
4
+ class Input
5
+
6
+ attr_reader :request
7
+
8
+ def initialize(req)
9
+ @request = req
10
+
11
+ # Copy params...
12
+ @params = Hash.new
13
+ req.params.each { |k,v| @params[k] = v }
14
+
15
+ # Copy headers...
16
+ @headers = Hash.new
17
+ req.env.each do |k,v|
18
+ @headers[k] = v if k =~ /^[A-Z]/ # Begin with capital
19
+ end
20
+ end
21
+
22
+ def get(key)
23
+ @params[key]
24
+ end
25
+
26
+ def put(key, value)
27
+ @params[key] = value
28
+ end
29
+
30
+ def remove(key)
31
+ @params.delete(key)
32
+ end
33
+
34
+ def getHeader(key)
35
+ @headers[key]
36
+ end
37
+
38
+ def headers
39
+ @headers.each do |k,v|
40
+ yield k
41
+ end
42
+ end
43
+
44
+ def keys
45
+ @params.each do |k,v|
46
+ yield k
47
+ end
48
+ end
49
+
50
+ def values
51
+ @params.each do |k,v|
52
+ yield k,v
53
+ end
54
+ end
55
+
56
+ def hasKey?(key)
57
+ @params.has_key?(key)
58
+ end
59
+
60
+ alias has_key? hasKey?
61
+ alias key? hasKey?
62
+
63
+ def hasProperty?(prop)
64
+ @request.class.public_instance_methods.each do |m|
65
+ return 1 if m == prop
66
+ end
67
+ nil
68
+ end
69
+
70
+ alias has_property? hasProperty?
71
+ alias has_prop? hasProperty?
72
+ alias hasProp? hasProperty?
73
+
74
+ def getProperty(prop)
75
+ @request.class.public_instance_methods.each do |m|
76
+ if m == prop then
77
+ return @request.send(prop)
78
+ end
79
+ end
80
+ nil
81
+ end
82
+
83
+ alias getProp getProperty
84
+ alias get_prop getProperty
85
+ alias get_property getProperty
86
+ alias property getProperty
87
+ alias prop getProperty
88
+ alias each values
89
+
90
+ alias [] get
91
+ alias []= put
92
+
93
+ end
94
+
95
+ end
96
+ end
97
+
98
+
99
+
@@ -0,0 +1,58 @@
1
+ module Mentawai
2
+ module Core
3
+
4
+ class InvocationChain
5
+
6
+ def initialize(action, actionName, innerAction)
7
+ @action = action
8
+ @actionName = actionName
9
+ @filters = Array.new
10
+ @innerAction = innerAction
11
+ end
12
+
13
+ def action
14
+ @action
15
+ end
16
+
17
+ def actionName
18
+ @actionName
19
+ end
20
+
21
+ def innerAction
22
+ @innerAction
23
+ end
24
+
25
+ def addFilter(filter)
26
+ @filters.push(filter)
27
+ end
28
+
29
+ def addFilters(filters)
30
+ filters.each do |f|
31
+ @filters.push(f)
32
+ end
33
+ end
34
+
35
+ def filters
36
+ @filters.each do |f|
37
+ yield f
38
+ end
39
+ end
40
+
41
+ def invoke
42
+
43
+ if !@filters.empty? then
44
+ f = @filters.shift
45
+ return f.filter(self)
46
+ end
47
+
48
+ if @innerAction != nil then
49
+ @action.send(@innerAction)
50
+ else
51
+ @action.execute
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,51 @@
1
+ module Mentawai
2
+ module Core
3
+
4
+ class Output
5
+
6
+ attr_reader :response
7
+
8
+ def initialize(res)
9
+ @response = res
10
+ @values = Hash.new
11
+ end
12
+
13
+ def get(key)
14
+ @values[key]
15
+ end
16
+
17
+ def put(key, value)
18
+ @values[key] = value
19
+ end
20
+
21
+ def hasKey?(key)
22
+ @values.has_key?(key)
23
+ end
24
+
25
+ alias has_key? hasKey?
26
+ alias key? hasKey?
27
+
28
+ def remove(key)
29
+ @values.delete(key)
30
+ end
31
+
32
+ def keys
33
+ @values.each do |k,v|
34
+ yield k
35
+ end
36
+ end
37
+
38
+ def values
39
+ @values.each do |k,v|
40
+ yield k,v
41
+ end
42
+ end
43
+
44
+ alias [] get
45
+ alias []= put
46
+ alias each values
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,75 @@
1
+ module Mentawai
2
+ module Core
3
+
4
+ class Session
5
+
6
+ attr_reader :request, :response
7
+
8
+ def initialize(req, res)
9
+ @request = req
10
+ @response = res
11
+ @session = req.env['rack.session']
12
+ @sdat = @session.instance_variable_get '@dat'
13
+ end
14
+
15
+ def sid
16
+ @sdat[0]
17
+ end
18
+
19
+ def get(key)
20
+ @session[key]
21
+ end
22
+
23
+ def put(key, value)
24
+
25
+ # Are we replacing an object?
26
+ if @session.key?(key) then
27
+ removed = @session[key]
28
+ if not value.equal?(removed) then
29
+ removed.removed_from_session(key) if removed.respond_to?(:removed_from_session)
30
+ end
31
+ end
32
+
33
+ @session[key] = value
34
+ value.added_to_session(key) if value.respond_to?(:added_to_session)
35
+ end
36
+
37
+ def remove(key)
38
+ removed = @session.delete(key)
39
+ removed.removed_from_session(key) if removed.respond_to?(:removed_from_session)
40
+ end
41
+
42
+ def hasKey?(key)
43
+ @session.has_key?(key)
44
+ end
45
+
46
+ alias has_key? hasKey?
47
+ alias key? hasKey?
48
+
49
+ def keys
50
+ @session.each do |k,v|
51
+ yield k
52
+ end
53
+ end
54
+
55
+ def values
56
+ @session.each do |k,v|
57
+ yield k,v
58
+ end
59
+ end
60
+
61
+ def reset
62
+ @sdat[1] = 0 # expire it!
63
+ end
64
+
65
+ alias [] get
66
+ alias []= put
67
+ alias delete remove
68
+ alias each values
69
+
70
+ end
71
+
72
+ end
73
+ end
74
+
75
+
@@ -0,0 +1,54 @@
1
+ module Mentawai
2
+ class Loader
3
+
4
+ def initialize(mentaPath = nil)
5
+ if mentaPath then
6
+ @file_mask = mentaPath + '/**/*.rb'
7
+ else
8
+ @file_mask = './Mentawai/**/*.rb'
9
+ end
10
+
11
+ puts "File mask: #{@file_mask}"
12
+ @files = { }
13
+
14
+ Dir.glob(@file_mask).each do |f|
15
+ next if f =~ /loader\.rb$/
16
+ @files[File.new(f)] = 0
17
+ end
18
+
19
+ raise "Cannot load Mentawai files: #{@file_mask}" if @files.size == 0
20
+
21
+ end
22
+
23
+ def showFiles
24
+ @files.each do |f,t|
25
+ puts "#{f.path}: #{t}"
26
+ end
27
+ end
28
+
29
+ def files_count
30
+ @files.size
31
+ end
32
+
33
+ alias size files_count
34
+ alias length files_count
35
+
36
+ def reloadFiles
37
+ count = 0
38
+ @files.each do |f,t|
39
+ if t == 0 then
40
+ puts "Loading #{f.path}" # first time
41
+ load f.path
42
+ count += 1
43
+ elsif t != f.mtime
44
+ puts "Reloading #{f.path}" # was modified
45
+ load f.path
46
+ count += 1
47
+ end
48
+ @files[f] = f.mtime # update modified time
49
+ end
50
+ count
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,17 @@
1
+ require 'mentawai/page/page_method'
2
+
3
+ module Mentawai
4
+ module Page
5
+ module Method
6
+
7
+ class Out < Mentawai::Page::PageMethod
8
+
9
+ def print
10
+ raise "Value attribute is mandatory!" if not arg?(:value)
11
+ find_value(arg[:value])
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end