rhodes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/History.txt +4 -0
- data/Manifest.txt +52 -0
- data/README.rdoc +2 -0
- data/Rakefile +33 -0
- data/bin/rhogen +8 -0
- data/generators/rhogen.rb +99 -0
- data/generators/templates/application/application.rb +4 -0
- data/generators/templates/application/index.html +25 -0
- data/generators/templates/model/config.rb +3 -0
- data/generators/templates/model/controller.rb +48 -0
- data/generators/templates/model/edit.erb +21 -0
- data/generators/templates/model/index.erb +10 -0
- data/generators/templates/model/new.erb +16 -0
- data/lib/ServeME.rb +7 -0
- data/lib/TestServe.rb +9 -0
- data/lib/builtinME.rb +481 -0
- data/lib/date.rb +1781 -0
- data/lib/date/format.rb +1313 -0
- data/lib/erb.rb +896 -0
- data/lib/find.rb +81 -0
- data/lib/rational.rb +19 -0
- data/lib/rho.rb +1 -0
- data/lib/rho/render.rb +9 -0
- data/lib/rho/renderME.rb +8 -0
- data/lib/rho/rho.rb +173 -0
- data/lib/rho/rhoapplication.rb +36 -0
- data/lib/rho/rhocontroller.rb +51 -0
- data/lib/rho/rhofsconnector.rb +39 -0
- data/lib/rho/rhofsconnectorME.rb +36 -0
- data/lib/rho/rhosupport.rb +139 -0
- data/lib/rhodes.rb +5 -0
- data/lib/rhofsconnector.rb +5 -0
- data/lib/rhom.rb +1 -0
- data/lib/rhom/rhom.rb +41 -0
- data/lib/rhom/rhom_db_adapter.rb +183 -0
- data/lib/rhom/rhom_db_adapterME.rb +91 -0
- data/lib/rhom/rhom_object.rb +53 -0
- data/lib/rhom/rhom_object_factory.rb +246 -0
- data/lib/singleton.rb +313 -0
- data/lib/time.rb +839 -0
- data/rhodes.gemspec +18 -0
- data/spec/app_generator_spec.rb +27 -0
- data/spec/generator_spec_helper.rb +12 -0
- data/spec/model_generator_spec.rb +28 -0
- data/spec/rho_spec.rb +28 -0
- data/spec/rhom_object_factory_spec.rb +147 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/stubs.rb +17 -0
- data/spec/syncdbtest.sqlite +0 -0
- data/tasks/rspec.rake +34 -0
- metadata +157 -0
data/lib/find.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#
|
2
|
+
# find.rb: the Find module for processing all files under a given directory.
|
3
|
+
#
|
4
|
+
|
5
|
+
#
|
6
|
+
# The +Find+ module supports the top-down traversal of a set of file paths.
|
7
|
+
#
|
8
|
+
# For example, to total the size of all files under your home directory,
|
9
|
+
# ignoring anything in a "dot" directory (e.g. $HOME/.ssh):
|
10
|
+
#
|
11
|
+
# require 'find'
|
12
|
+
#
|
13
|
+
# total_size = 0
|
14
|
+
#
|
15
|
+
# Find.find(ENV["HOME"]) do |path|
|
16
|
+
# if FileTest.directory?(path)
|
17
|
+
# if File.basename(path)[0] == ?.
|
18
|
+
# Find.prune # Don't look any further into this directory.
|
19
|
+
# else
|
20
|
+
# next
|
21
|
+
# end
|
22
|
+
# else
|
23
|
+
# total_size += FileTest.size(path)
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
module Find
|
28
|
+
|
29
|
+
#
|
30
|
+
# Calls the associated block with the name of every file and directory listed
|
31
|
+
# as arguments, then recursively on their subdirectories, and so on.
|
32
|
+
#
|
33
|
+
# See the +Find+ module documentation for an example.
|
34
|
+
#
|
35
|
+
def find(*paths) # :yield: path
|
36
|
+
block_given? or return enum_for(__method__, *paths)
|
37
|
+
|
38
|
+
paths.collect!{|d| raise Errno::ENOENT unless File.exist?(d); d.dup}
|
39
|
+
while file = paths.shift
|
40
|
+
catch(:prune) do
|
41
|
+
yield file.dup.taint
|
42
|
+
next unless File.exist? file
|
43
|
+
begin
|
44
|
+
if File.lstat(file).directory? then
|
45
|
+
d = Dir.open(file)
|
46
|
+
begin
|
47
|
+
for f in d
|
48
|
+
next if f == "." or f == ".."
|
49
|
+
if File::ALT_SEPARATOR and file =~ /^(?:[\/\\]|[A-Za-z]:[\/\\]?)$/ then
|
50
|
+
f = file + f
|
51
|
+
elsif file == "/" then
|
52
|
+
f = "/" + f
|
53
|
+
else
|
54
|
+
f = File.join(file, f)
|
55
|
+
end
|
56
|
+
paths.unshift f.untaint
|
57
|
+
end
|
58
|
+
ensure
|
59
|
+
d.close
|
60
|
+
end
|
61
|
+
end
|
62
|
+
rescue Errno::ENOENT, Errno::EACCES
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Skips the current file or directory, restarting the loop with the next
|
70
|
+
# entry. If the current file is a directory, that directory will not be
|
71
|
+
# recursively entered. Meaningful only within the block associated with
|
72
|
+
# Find::find.
|
73
|
+
#
|
74
|
+
# See the +Find+ module documentation for an example.
|
75
|
+
#
|
76
|
+
def prune
|
77
|
+
throw :prune
|
78
|
+
end
|
79
|
+
|
80
|
+
module_function :find, :prune
|
81
|
+
end
|
data/lib/rational.rb
ADDED
data/lib/rho.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rho/rho'
|
data/lib/rho/render.rb
ADDED
data/lib/rho/renderME.rb
ADDED
data/lib/rho/rho.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'rho/rhoapplication'
|
3
|
+
require 'rhom'
|
4
|
+
require 'rhofsconnector'
|
5
|
+
|
6
|
+
module Rho
|
7
|
+
class RHO
|
8
|
+
APPLICATIONS = {}
|
9
|
+
|
10
|
+
def initialize(app_base_path=nil)
|
11
|
+
puts "Calling RHO.initialize"
|
12
|
+
Rhom::RhomDbAdapter::open(Rho::RhoFSConnector::get_db_fullpathname)
|
13
|
+
if app_base_path
|
14
|
+
process_model_dirs(app_base_path)
|
15
|
+
else
|
16
|
+
process_model_dirs(RhoApplication::get_base_app_path)
|
17
|
+
end
|
18
|
+
init_sources
|
19
|
+
end
|
20
|
+
|
21
|
+
# make sure we close the database file
|
22
|
+
def self.finalize
|
23
|
+
Rhom::RhomDbAdapter::close
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return the directories where we need to load configuration files
|
27
|
+
def process_model_dirs(app_base_path=nil)
|
28
|
+
Rho::RhoFSConnector::enum_files(app_base_path,'config.rb') do |path|
|
29
|
+
require path
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# setup the sources table and model attributes for all applications
|
34
|
+
def init_sources
|
35
|
+
if defined? Rho::RhoConfig::sources
|
36
|
+
Rhom::RhomDbAdapter::delete_all_from_table('sources')
|
37
|
+
src_attribs = []
|
38
|
+
attribs_empty = false
|
39
|
+
|
40
|
+
# quick and dirty way to get unique array of hashes
|
41
|
+
uniq_sources = Rho::RhoConfig::sources.values.inject([]) { |result,h|
|
42
|
+
result << h unless result.include?(h); result
|
43
|
+
}
|
44
|
+
|
45
|
+
# generate unique source list in databse for sync
|
46
|
+
uniq_sources.each do |source|
|
47
|
+
src_id = source['source_id']
|
48
|
+
url = source['url']
|
49
|
+
Rhom::RhomDbAdapter::insert_into_table('sources',
|
50
|
+
{"source_id"=>src_id,"source_url"=>url})
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_app(appname)
|
56
|
+
if (APPLICATIONS[appname].nil?)
|
57
|
+
require RhoApplication::get_app_path(appname)+'application'
|
58
|
+
APPLICATIONS[appname] = Object.const_get(appname+'Application').new
|
59
|
+
end
|
60
|
+
APPLICATIONS[appname]
|
61
|
+
end
|
62
|
+
|
63
|
+
def serve(req)
|
64
|
+
begin
|
65
|
+
puts 'inside RHO.serve...'
|
66
|
+
res = init_response
|
67
|
+
get_app(req['application']).send :serve, req, res
|
68
|
+
return send_response(res)
|
69
|
+
rescue Exception => e
|
70
|
+
return send_error(e.message)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def serve_hash(req)
|
75
|
+
begin
|
76
|
+
puts 'inside RHO.serve...'
|
77
|
+
res = init_response
|
78
|
+
get_app(req['application']).send :serve, req, res
|
79
|
+
return send_response_hash(res)
|
80
|
+
rescue Exception => e
|
81
|
+
return send_error(e.message,500,true)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def init_response(status=200,message="OK",body="")
|
86
|
+
res = Hash.new
|
87
|
+
res['status'] = status
|
88
|
+
res['message'] = message
|
89
|
+
res['headers'] =
|
90
|
+
{
|
91
|
+
'Date' => Time.now.httpdate,
|
92
|
+
'Content-Type' => 'text/html',
|
93
|
+
'Content-Length' => 0,
|
94
|
+
'Connection' => 'close'
|
95
|
+
}
|
96
|
+
res['request-body'] = body
|
97
|
+
res
|
98
|
+
end
|
99
|
+
|
100
|
+
CR = "\x0d"
|
101
|
+
LF = "\x0a"
|
102
|
+
CRLF = "\x0d\x0a"
|
103
|
+
|
104
|
+
def send_response(res)
|
105
|
+
res['headers']['Content-Length'] = res['request-body'].nil? ? 0 : res['request-body'].length
|
106
|
+
data = "HTTP/1.1 #{res['status'].to_s} #{res['message']}" + CRLF
|
107
|
+
res['headers'].each{|key, value|
|
108
|
+
tmp = key.gsub(/\bwww|^te$|\b\w/){|s| s.upcase }
|
109
|
+
data << "#{tmp}: #{value}" << CRLF
|
110
|
+
}
|
111
|
+
data << CRLF
|
112
|
+
data << res['request-body']
|
113
|
+
data
|
114
|
+
end
|
115
|
+
|
116
|
+
def send_response_hash(res)
|
117
|
+
resp = Hash.new
|
118
|
+
res['headers']['Content-Length'] = res['request-body'].nil? ? 0 : res['request-body'].length
|
119
|
+
res['headers'].each{|key, value|
|
120
|
+
tmp = key.gsub(/\bwww|^te$|\b\w/){|s| s.upcase }
|
121
|
+
resp[tmp] = value
|
122
|
+
}
|
123
|
+
resp['request-body'] = res['request-body']
|
124
|
+
resp['status'] = res['status']
|
125
|
+
resp['message'] = res['message']
|
126
|
+
|
127
|
+
resp
|
128
|
+
end
|
129
|
+
|
130
|
+
def send_error(msg="",status=500,hash=false)
|
131
|
+
body=''
|
132
|
+
body << <<-_HTML_STRING_
|
133
|
+
<html>
|
134
|
+
<head>
|
135
|
+
<title>Server Error</title>
|
136
|
+
<meta name="viewport" content="width=320"/>
|
137
|
+
</head>
|
138
|
+
<body>
|
139
|
+
<p>
|
140
|
+
_HTML_STRING_
|
141
|
+
body << 'Error message: ' << msg
|
142
|
+
body << <<-_HTML_STRING_
|
143
|
+
</p>
|
144
|
+
</body>
|
145
|
+
</html>
|
146
|
+
|
147
|
+
_HTML_STRING_
|
148
|
+
if ( hash )
|
149
|
+
send_response_hash(init_response(status,"Server error",body))
|
150
|
+
else
|
151
|
+
send_response(init_response(status,"Server error",body))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end # RHO
|
155
|
+
|
156
|
+
# Generic configuration class which accepts hashes with unique keys
|
157
|
+
class RhoConfig
|
158
|
+
@@sources = {}
|
159
|
+
class << self
|
160
|
+
def sources
|
161
|
+
@@sources
|
162
|
+
end
|
163
|
+
|
164
|
+
def add_source(modelname, new_source=nil)
|
165
|
+
if new_source
|
166
|
+
unless @@sources[new_source]
|
167
|
+
@@sources[modelname] = new_source
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end # RhoConfig
|
173
|
+
end # Rho
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rhom'
|
2
|
+
require 'rhofsconnector'
|
3
|
+
|
4
|
+
module Rho
|
5
|
+
class RhoApplication
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
if @rhom.nil?
|
9
|
+
@rhom = Rhom::Rhom.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
|
15
|
+
def get_app_path(appname)
|
16
|
+
Rho::RhoFSConnector::get_app_path(appname)
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_base_app_path
|
20
|
+
Rho::RhoFSConnector::get_base_app_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_model_path(appname, modelname)
|
24
|
+
Rho::RhoFSConnector::get_model_path(appname, modelname)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def serve(req,res)
|
30
|
+
req[:modelpath] = self.class.get_model_path req['application'], req['model']
|
31
|
+
require req[:modelpath]+'controller'
|
32
|
+
res['request-body'] = (Object.const_get(req['model']+'Controller').new).send :serve, @rhom, req, res
|
33
|
+
end
|
34
|
+
|
35
|
+
end # RhoApplication
|
36
|
+
end # Rho
|
@@ -0,0 +1,51 @@
|
|
1
|
+
if defined? RHO_ME
|
2
|
+
require 'rho/renderME'
|
3
|
+
else
|
4
|
+
require 'rho/render'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rho/rhosupport'
|
8
|
+
|
9
|
+
module Rho
|
10
|
+
class RhoController
|
11
|
+
|
12
|
+
def default_action
|
13
|
+
return Hash['GET','show','PUT','update','POST','update',
|
14
|
+
'DELETE','delete'][@request['request-method']] unless @request['id'].nil?
|
15
|
+
return Hash['GET','index','POST','create'][@request['request-method']]
|
16
|
+
end
|
17
|
+
|
18
|
+
def serve(object_mapping,req,res)
|
19
|
+
@request, @response = req, res;
|
20
|
+
@object_mapping = object_mapping
|
21
|
+
@params = RhoSupport::query_params req
|
22
|
+
send req['action'].nil? ? default_action : req['action']
|
23
|
+
end
|
24
|
+
|
25
|
+
def link_to(name,action,id=nil,confirm=nil)
|
26
|
+
action = action.to_s
|
27
|
+
if (action != 'delete')
|
28
|
+
"<a href=\"#{url_for(action,id)}\">#{name}</a>"
|
29
|
+
else
|
30
|
+
"<a href=\"#{url_for(action,id)}\" onclick=\""+ #if (confirm('#{confirm}')) {
|
31
|
+
"var f = document.createElement('form'); f.style.display = 'none';" +
|
32
|
+
"this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;f.submit();"+
|
33
|
+
"return false;\">#{name}</a>"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def url_for(action,id=nil)
|
38
|
+
action = action.to_s
|
39
|
+
amurl = '/'+@request['application']+'/'+@request['model']
|
40
|
+
return amurl if action == 'create' or action == 'index'
|
41
|
+
return amurl +'/'+ (id.nil? ? action.to_s : id.to_s + '/' + action.to_s)
|
42
|
+
end
|
43
|
+
|
44
|
+
def redirect(action,id=nil)
|
45
|
+
@response['status'] = 302
|
46
|
+
@response['headers']['Location'] = url_for(action,id)
|
47
|
+
@response['message'] = 'Moved temporarily'
|
48
|
+
return ''
|
49
|
+
end
|
50
|
+
end # RhoController
|
51
|
+
end # Rho
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'find'
|
2
|
+
|
3
|
+
module Rho
|
4
|
+
class RhoFSConnector
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def get_app_path(appname)
|
9
|
+
File.join(File.dirname(File.expand_path(__FILE__)), '../../apps/'+appname+'/')
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_base_app_path
|
13
|
+
File.join(File.dirname(File.expand_path(__FILE__)), '../../apps/')
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_model_path(appname, modelname)
|
17
|
+
File.join(File.dirname(File.expand_path(__FILE__)), '../../apps/'+appname+'/'+modelname+'/')
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_db_fullpathname
|
21
|
+
if defined? SYNC_DB_FILE
|
22
|
+
File.join(File.dirname(File.expand_path(__FILE__)), SYNC_DB_FILE)
|
23
|
+
else
|
24
|
+
File.join(File.dirname(File.expand_path(__FILE__)), '../../db/syncdb.sqlite')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def enum_files(paths, filename) # :yield: path
|
29
|
+
Find.find(paths) do |path|
|
30
|
+
if File.basename(path) == filename
|
31
|
+
yield path
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end # RhoApplication
|
39
|
+
end # Rho
|
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
module Rho
|
3
|
+
class RhoFSConnector
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def get_app_path(appname)
|
8
|
+
'apps/'+appname+'/'
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_base_app_path
|
12
|
+
'apps/'
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_model_path(appname, modelname)
|
16
|
+
'apps/'+appname+'/'+modelname+'/'
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_db_fullpathname
|
20
|
+
if defined? SYNC_DB_FILE
|
21
|
+
SYNC_DB_FILE
|
22
|
+
else
|
23
|
+
'syncdb_.dbs'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def enum_files(paths, filename) # :yield: path
|
28
|
+
yield get_app_path('Rhosugar/Account') + filename
|
29
|
+
yield get_app_path('Rhosugar/Case') + filename
|
30
|
+
yield get_app_path('Rhosugar/Employee') + filename
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end # RhoApplication
|
36
|
+
end # Rho
|