rhodes 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +4 -0
  3. data/Manifest.txt +52 -0
  4. data/README.rdoc +2 -0
  5. data/Rakefile +33 -0
  6. data/bin/rhogen +8 -0
  7. data/generators/rhogen.rb +99 -0
  8. data/generators/templates/application/application.rb +4 -0
  9. data/generators/templates/application/index.html +25 -0
  10. data/generators/templates/model/config.rb +3 -0
  11. data/generators/templates/model/controller.rb +48 -0
  12. data/generators/templates/model/edit.erb +21 -0
  13. data/generators/templates/model/index.erb +10 -0
  14. data/generators/templates/model/new.erb +16 -0
  15. data/lib/ServeME.rb +7 -0
  16. data/lib/TestServe.rb +9 -0
  17. data/lib/builtinME.rb +481 -0
  18. data/lib/date.rb +1781 -0
  19. data/lib/date/format.rb +1313 -0
  20. data/lib/erb.rb +896 -0
  21. data/lib/find.rb +81 -0
  22. data/lib/rational.rb +19 -0
  23. data/lib/rho.rb +1 -0
  24. data/lib/rho/render.rb +9 -0
  25. data/lib/rho/renderME.rb +8 -0
  26. data/lib/rho/rho.rb +173 -0
  27. data/lib/rho/rhoapplication.rb +36 -0
  28. data/lib/rho/rhocontroller.rb +51 -0
  29. data/lib/rho/rhofsconnector.rb +39 -0
  30. data/lib/rho/rhofsconnectorME.rb +36 -0
  31. data/lib/rho/rhosupport.rb +139 -0
  32. data/lib/rhodes.rb +5 -0
  33. data/lib/rhofsconnector.rb +5 -0
  34. data/lib/rhom.rb +1 -0
  35. data/lib/rhom/rhom.rb +41 -0
  36. data/lib/rhom/rhom_db_adapter.rb +183 -0
  37. data/lib/rhom/rhom_db_adapterME.rb +91 -0
  38. data/lib/rhom/rhom_object.rb +53 -0
  39. data/lib/rhom/rhom_object_factory.rb +246 -0
  40. data/lib/singleton.rb +313 -0
  41. data/lib/time.rb +839 -0
  42. data/rhodes.gemspec +18 -0
  43. data/spec/app_generator_spec.rb +27 -0
  44. data/spec/generator_spec_helper.rb +12 -0
  45. data/spec/model_generator_spec.rb +28 -0
  46. data/spec/rho_spec.rb +28 -0
  47. data/spec/rhom_object_factory_spec.rb +147 -0
  48. data/spec/spec.opts +1 -0
  49. data/spec/spec_helper.rb +14 -0
  50. data/spec/stubs.rb +17 -0
  51. data/spec/syncdbtest.sqlite +0 -0
  52. data/tasks/rspec.rake +34 -0
  53. 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
@@ -0,0 +1,19 @@
1
+ class Fixnum
2
+
3
+ alias quof fdiv
4
+ alias rdiv quo
5
+
6
+ alias power! **
7
+ alias rpower **
8
+
9
+ end
10
+
11
+ class Bignum
12
+
13
+ alias quof fdiv
14
+ alias rdiv quo
15
+
16
+ alias power! **
17
+ alias rpower **
18
+
19
+ end
data/lib/rho.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rho/rho'
data/lib/rho/render.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'erb'
2
+
3
+ module Rho
4
+ class RhoController
5
+ def render(view)
6
+ ERB.new(IO.read(@request[:modelpath]+view.to_s+'.erb')).result(binding)
7
+ end
8
+ end # RhoController
9
+ end # Rho
@@ -0,0 +1,8 @@
1
+
2
+ module Rho
3
+ class RhoController
4
+ def render(view)
5
+ eval(@request[:modelpath]+view.to_s+'_erb', binding )
6
+ end
7
+ end # RhoController
8
+ end # Rho
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