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
@@ -0,0 +1,139 @@
1
+ module Rho
2
+ module RhoSupport
3
+
4
+ class << self
5
+ def _unescape(str, regex) str.gsub(regex){ $1.hex.chr } end
6
+
7
+ ESCAPED = /%([0-9a-fA-F]{2})/
8
+
9
+ def unescape_form(str)
10
+ _unescape(str.gsub(/\+/, " "), ESCAPED)
11
+ end
12
+
13
+ def parse_query_parameters(query_string)
14
+ return {} if query_string.nil?
15
+
16
+ pairs = query_string.split('&').collect do |chunk|
17
+ next if chunk.empty?
18
+ key, value = chunk.split('=', 2)
19
+ next if key.empty?
20
+ value = value.nil? ? nil : unescape_form(value)
21
+ [ unescape_form(key), value ]
22
+ end.compact
23
+
24
+ UrlEncodedPairParser.new(pairs).result
25
+ end
26
+
27
+ def query_params(req)
28
+ params = {}
29
+ unless req['id'].nil?
30
+ params['id'] = req['id']
31
+ end
32
+ unless req['request-query'].nil? or req['request-query'].length == 0
33
+ params.merge!(parse_query_parameters(req['request-query']))
34
+ end
35
+ unless req['headers'].nil? or req['headers']['Content-Type'].nil?
36
+ if 'application/x-www-form-urlencoded'.eql? req['headers']['Content-Type']
37
+ params.merge!(parse_query_parameters(req['request-body']))
38
+ end
39
+ end
40
+ puts "Params: " + params.to_s unless params.empty?
41
+ params
42
+ end
43
+ end
44
+
45
+ class UrlEncodedPairParser < StringScanner #:nodoc:
46
+ attr_reader :top, :parent, :result
47
+
48
+ def initialize(pairs = [])
49
+ super('')
50
+ @result = {}
51
+ pairs.each { |key, value| parse(key, value) }
52
+ end
53
+
54
+ KEY_REGEXP = %r{([^\[\]=&]+)}
55
+ BRACKETED_KEY_REGEXP = %r{\[([^\[\]=&]+)\]}
56
+
57
+ # Parse the query string
58
+ def parse(key, value)
59
+ self.string = key
60
+ @top, @parent = result, nil
61
+
62
+ # First scan the bare key
63
+ key = scan(KEY_REGEXP) or return
64
+ key = post_key_check(key)
65
+
66
+ # Then scan as many nestings as present
67
+ until eos?
68
+ r = scan(BRACKETED_KEY_REGEXP) or return
69
+ key = self[1]
70
+ key = post_key_check(key)
71
+ end
72
+
73
+ bind(key, value)
74
+ end
75
+
76
+ private
77
+ # After we see a key, we must look ahead to determine our next action. Cases:
78
+ #
79
+ # [] follows the key. Then the value must be an array.
80
+ # = follows the key. (A value comes next)
81
+ # & or the end of string follows the key. Then the key is a flag.
82
+ # otherwise, a hash follows the key.
83
+ def post_key_check(key)
84
+ if scan(/\[\]/) # a[b][] indicates that b is an array
85
+ container(key, Array)
86
+ nil
87
+ elsif check(/\[[^\]]/) # a[b] indicates that a is a hash
88
+ container(key, Hash)
89
+ nil
90
+ else # End of key? We do nothing.
91
+ key
92
+ end
93
+ end
94
+
95
+ # Add a container to the stack.
96
+ def container(key, klass)
97
+ type_conflict! klass, top[key] if top.is_a?(Hash) && top.key?(key) && ! top[key].is_a?(klass)
98
+ value = bind(key, klass.new)
99
+ type_conflict! klass, value unless value.is_a?(klass)
100
+ push(value)
101
+ end
102
+
103
+ # Push a value onto the 'stack', which is actually only the top 2 items.
104
+ def push(value)
105
+ @parent, @top = @top, value
106
+ end
107
+
108
+ # Bind a key (which may be nil for items in an array) to the provided value.
109
+ def bind(key, value)
110
+ if top.is_a? Array
111
+ if key
112
+ if top[-1].is_a?(Hash) && ! top[-1].key?(key)
113
+ top[-1][key] = value
114
+ else
115
+ top << {key => value}.with_indifferent_access
116
+ push top.last
117
+ value = top[key]
118
+ end
119
+ else
120
+ top << value
121
+ end
122
+ elsif top.is_a? Hash
123
+ #key = CGI.unescape(key)
124
+ parent << (@top = {}) if top.key?(key) && parent.is_a?(Array)
125
+ top[key] ||= value
126
+ return top[key]
127
+ else
128
+ raise ArgumentError, "Don't know what to do: top is #{top.inspect}"
129
+ end
130
+
131
+ return value
132
+ end
133
+
134
+ def type_conflict!(klass, value)
135
+ raise TypeError, "Conflicting types for parameter containers. Expected an instance of #{klass} but found an instance of #{value.class}. This can be caused by colliding Array and Hash parameters like qs[]=value&qs[key]=value. (The parameters received were #{value.inspect}.)"
136
+ end
137
+ end
138
+ end # RhoSupport
139
+ end # Rho
data/lib/rhodes.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Rhodes
2
+ unless defined? Rhodes::VERSION
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ if defined? RHO_ME
2
+ require 'rho/rhofsconnectorME.rb'
3
+ else
4
+ require 'rho/rhofsconnector.rb'
5
+ end
data/lib/rhom.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rhom/rhom'
data/lib/rhom/rhom.rb ADDED
@@ -0,0 +1,41 @@
1
+ #
2
+ # rhom.rb
3
+ # rhodes
4
+ # This module represents the rhodes mini OM
5
+ #
6
+ # Copyright (C) 2008 Lars Burgess. All rights reserved.
7
+ #
8
+ # This program is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #
21
+
22
+ require 'rhom/rhom_object_factory'
23
+ require 'rhom/rhom_object'
24
+ if defined? RHO_ME
25
+ require 'rhom/rhom_db_adapterME'
26
+ else
27
+ require 'rhom/rhom_db_adapter'
28
+ end
29
+
30
+ module Rhom
31
+ TABLE_NAME = 'object_values'
32
+
33
+ class Rhom
34
+ include RhomObject
35
+ attr_accessor :factory
36
+
37
+ def initialize
38
+ @factory = RhomObjectFactory.new
39
+ end
40
+ end # Rhom
41
+ end # Rhom
@@ -0,0 +1,183 @@
1
+ #
2
+ # rhom_db_adapter.rb
3
+ # rhodes
4
+ #
5
+ # Copyright (C) 2008 Lars Burgess. All rights reserved.
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+ $:.unshift(File.join(File.dirname(__FILE__), '../../'))
21
+ require 'sqlite3/database'
22
+
23
+ module Rhom
24
+ class RhomDbAdapter
25
+
26
+ @@database = nil
27
+
28
+ class << self
29
+
30
+ # maintains a single database connection
31
+ def open(dbfile=nil)
32
+ puts "DB name = " + dbfile.inspect
33
+ unless @@database or dbfile.nil?
34
+ @@database = SQLite3::Database.new(dbfile)
35
+ end
36
+ end
37
+
38
+ # closes the database if and only if it is open
39
+ def close
40
+ if @@database and not @@database.closed?
41
+ @@database.close
42
+ @@database = nil
43
+ else
44
+ return false
45
+ end
46
+ return true
47
+ end
48
+
49
+ # execute a sql statement
50
+ # optionally, disable the factory processing
51
+ # which returns the result array directly
52
+ def execute_sql(sql=nil)
53
+ result = []
54
+ if sql
55
+ puts 'query is ' + sql
56
+ # Make sure we lock the sync engine's mutex
57
+ # before we perform a database transaction.
58
+ # This prevents concurrency issues.
59
+ begin
60
+ SyncEngine::lock_sync_mutex
61
+ # execute sql statement inside of transaction
62
+ # result is returned as an array of hashes
63
+ @@database.transaction unless @@database.transaction_active?
64
+ @@database.results_as_hash = true
65
+ result = @@database.execute sql
66
+ @@database.commit
67
+ SyncEngine::unlock_sync_mutex
68
+ rescue Exception => e
69
+ puts "exception when running query: #{e}"
70
+ # make sure we unlock even if there's an error!
71
+ SyncEngine::unlock_sync_mutex
72
+ end
73
+ end
74
+ puts "returned #{result.length.to_s} records..."
75
+ result
76
+ end
77
+
78
+ # generates where clause based on hash
79
+ def where_str(condition)
80
+ cond = ""
81
+ condition.each do |key,value|
82
+ val = value.is_a?(String) ? "'#{value}'" : "#{value}"
83
+ cond << " #{key} = #{val} and"
84
+ end
85
+ cond[0..cond.length - 5]
86
+ end
87
+
88
+ # generates value clause based on hash
89
+ def vals_str(values)
90
+ vals = ""
91
+ values.each do |key,value|
92
+ val = value.is_a?(String) ? "'#{value}'" : "#{value}"
93
+ vals << "#{key} = #{val},"
94
+ end
95
+ vals[0..vals.length - 2]
96
+ end
97
+
98
+ # support for select statements
99
+ # this function takes table name, columns (as a comma-separated list),
100
+ # condition (as a hash), and params (as a hash)
101
+ # example usage is the following:
102
+ # select_from_table('object_values', '*', {"source_id"=>2,"update_type"=>'query'},
103
+ # {"order by"=>'object'})
104
+ # this would return all columns where source_id = 2 and update_type = 'query' ordered
105
+ # by the "object" column
106
+ def select_from_table(table=nil,columns=nil,condition=nil,params=nil)
107
+ query = nil
108
+ if table and columns and condition
109
+ if params and params['distinct']
110
+ query = "select distinct #{columns} from #{table} where #{where_str(condition)}"
111
+ elsif params and params['order by']
112
+ query = "select #{columns} from #{table} where #{where_str(condition)} \
113
+ order by #{params['order by']}"
114
+ else
115
+ query = "select #{columns} from #{table} where #{where_str(condition)}"
116
+ end
117
+ elsif table and columns
118
+ query = "select #{columns} from #{table}"
119
+ end
120
+ execute_sql query
121
+ end
122
+
123
+ # inserts a single row into the database
124
+ # takes the table name and values (hash) as arguments
125
+ # exmaple usage is the following:
126
+ # insert_into_table('object_values, {"source_id"=>1,"object"=>"some-object","update_type"=>'delete'})
127
+ # this would execute the following sql:
128
+ # insert into object_values (source_id,object,update_type) values (1,'some-object','delete');
129
+ def insert_into_table(table=nil,values=nil)
130
+ query = nil
131
+ cols = ""
132
+ vals = ""
133
+ if table and values
134
+ values.each do |key,val|
135
+ value = val.is_a?(Fixnum) ? "#{val}," : "'#{val}',"
136
+ cols << "#{key},"
137
+ vals << value
138
+ end
139
+ cols = cols[0..cols.length - 2]
140
+ vals = vals[0..vals.length - 2]
141
+ query = "insert into #{table} (#{cols}) values (#{vals})"
142
+ end
143
+ execute_sql query
144
+ end
145
+
146
+ # deletes rows from a table which satisfy condition (hash)
147
+ # example usage is the following:
148
+ # delete_from_table('object_values',{"object"=>"some-object"})
149
+ # this would execute the following sql:
150
+ # delete from object_values where object="some-object"
151
+ def delete_from_table(table=nil,condition=nil)
152
+ query = nil
153
+ if table and condition
154
+ query = "delete from #{table} where #{where_str(condition)}"
155
+ end
156
+ execute_sql query
157
+ end
158
+
159
+ # deletes all rows from a given table
160
+ def delete_all_from_table(table=nil)
161
+ query = nil
162
+ if table
163
+ query = "delete from #{table}"
164
+ end
165
+ execute_sql query
166
+ end
167
+
168
+ # updates values (hash) in a given table which satisfy condition (hash)
169
+ # example usage is the following:
170
+ # update_into_table('object_values',{"value"=>"Electronics"},{"object"=>"some-object", "attrib"=>"industry"})
171
+ # this executes the following sql:
172
+ # update table object_values set value='Electronics' where object='some-object' and attrib='industry';
173
+ def update_into_table(table=nil,values=nil,condition=nil)
174
+ query = nil
175
+ vals = values.nil? ? nil : vals_str(values)
176
+ if table and condition and vals
177
+ query = "update #{table} set #{vals} where #{where_str(condition)}"
178
+ end
179
+ execute_sql query
180
+ end
181
+ end # class methods
182
+ end # RhomDbAdapter
183
+ end # Rhom
@@ -0,0 +1,91 @@
1
+ #
2
+ # rhom_db_adapter.rb
3
+ # rhodes
4
+ #
5
+ # Copyright (C) 2008 Lars Burgess. All rights reserved.
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+ module Rhom
21
+ class RhomDbAdapter
22
+
23
+ @@database = nil
24
+
25
+ class << self
26
+ def open(dbfile=nil)
27
+ puts "DB name = " + dbfile.inspect
28
+ unless @@database or dbfile.nil?
29
+ db = DbAdapter.new(dbfile)
30
+ @@database = db
31
+ end
32
+
33
+ end
34
+
35
+ def close
36
+ if @@database and not @@database.closed?
37
+ @@database.close
38
+ @@database = nil
39
+ else
40
+ return false
41
+ end
42
+ return true
43
+ end
44
+
45
+ # execute a sql statement
46
+ # optionally, disable the factory processing
47
+ # which returns the result array directly
48
+ def execute_sql
49
+ result = []
50
+ # Make sure we lock the sync engine's mutex
51
+ # before we perform a database transaction.
52
+ # This prevents concurrency issues.
53
+ begin
54
+ SyncEngine::lock_sync_mutex
55
+ result = yield
56
+ SyncEngine::unlock_sync_mutex
57
+ rescue Exception => e
58
+ puts "exception when running query: #{e}"
59
+ # make sure we unlock even if there's an error!
60
+ SyncEngine::unlock_sync_mutex
61
+ end
62
+ puts "returned #{result.length.to_s} records..."
63
+ result
64
+ end
65
+
66
+ def select_from_table(table=nil,columns=nil,condition=nil,params=nil)
67
+ execute_sql { @@database.selectFromTable(table, columns, condition, params) }
68
+ end
69
+
70
+ def insert_into_table(table=nil,values=nil)
71
+ execute_sql { @@database.insertIntoTable(table, values) }
72
+ end
73
+
74
+ def delete_from_table(table=nil,condition=nil)
75
+ execute_sql { @@database.deleteFromTable(table, condition) }
76
+ end
77
+
78
+ def delete_all_from_table(table=nil)
79
+ execute_sql { @@database.deleteAllFromTable(table) }
80
+ end
81
+
82
+ def update_into_table(table=nil,values=nil,condition=nil)
83
+ execute_sql { @@database.updateIntoTable(table, values, condition) }
84
+ end
85
+ end # class methods
86
+ end # RhomDbAdapter
87
+ end # Rhom
88
+
89
+ at_exit do
90
+ Rhom::RhomDbAdapter::close
91
+ end