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