rhodes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|