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