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.
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