rhodes 0.1.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/.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
|