nitro 0.12.0 → 0.13.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 (193) hide show
  1. data/{ChangeLog → CHANGELOG} +137 -0
  2. data/INSTALL +1 -2
  3. data/README +1 -1
  4. data/Rakefile +10 -61
  5. data/benchmark/{nitro/bench.rb → bench.rb} +1 -1
  6. data/benchmark/{nitro/simple-webrick-n-200.txt → simple-webrick-n-200.txt} +0 -0
  7. data/benchmark/{nitro/static-webrick-n-200.txt → static-webrick-n-200.txt} +0 -0
  8. data/benchmark/{nitro/tiny-lhttpd-n-200-c-5.txt → tiny-lhttpd-n-200-c-5.txt} +0 -0
  9. data/benchmark/{nitro/tiny-webrick-n-200-c-5.txt → tiny-webrick-n-200-c-5.txt} +0 -0
  10. data/benchmark/{nitro/tiny-webrick-n-200.txt → tiny-webrick-n-200.txt} +0 -0
  11. data/benchmark/{nitro/tiny2-webrick-n-200.txt → tiny2-webrick-n-200.txt} +0 -0
  12. data/doc/{ChangeLog.1 → CHANGELOG.1} +0 -0
  13. data/{RELEASES → doc/RELEASES} +46 -0
  14. data/doc/faq.txt +7 -0
  15. data/examples/README.windows +1 -1
  16. data/examples/ajax/controller.rb +21 -0
  17. data/examples/ajax/public/index.xhtml +70 -0
  18. data/examples/ajax/public/js/ajax.js +64 -0
  19. data/examples/ajax/run.rb +16 -0
  20. data/examples/blog/README +6 -3
  21. data/examples/blog/conf/apache.conf +2 -2
  22. data/examples/blog/conf/lhttpd.conf +2 -2
  23. data/examples/blog/log/apache.error_log +777 -0
  24. data/examples/blog/{root → public}/base.xsl +0 -0
  25. data/examples/blog/{root → public}/fcgi.rb +0 -0
  26. data/examples/blog/{root → public}/m/bubbles.gif +0 -0
  27. data/examples/blog/{root → public}/m/comments_curve.gif +0 -0
  28. data/examples/blog/{root → public}/m/down.gif +0 -0
  29. data/examples/blog/{root → public}/m/footer_bg.gif +0 -0
  30. data/examples/blog/{root → public}/m/garrow.gif +0 -0
  31. data/examples/blog/{root → public}/m/gbull.gif +0 -0
  32. data/examples/blog/{root → public}/m/grbull.gif +0 -0
  33. data/examples/blog/{root → public}/m/h1_bg.gif +0 -0
  34. data/examples/blog/{root → public}/m/header_bg.gif +0 -0
  35. data/examples/blog/{root → public}/m/nitro.gif +0 -0
  36. data/examples/blog/{root → public}/m/obull.gif +0 -0
  37. data/examples/blog/{root → public}/m/page_bg.gif +0 -0
  38. data/examples/blog/{root → public}/m/rss.gif +0 -0
  39. data/examples/blog/{root → public}/m/side_title_bg.gif +0 -0
  40. data/examples/blog/{root → public}/m/sidebar_bg.gif +0 -0
  41. data/examples/{no_xsl_blog/root → blog/public}/style.css +6 -0
  42. data/examples/blog/run.rb +10 -12
  43. data/examples/blog/{lib → src}/blog.rb +3 -3
  44. data/examples/blog/{lib/blog → src}/controller.rb +13 -2
  45. data/examples/blog/src/mailer.rb +23 -0
  46. data/examples/blog/{lib/blog/model.rb → src/models/blog.rb} +4 -7
  47. data/examples/blog/src/models/content.rb +52 -0
  48. data/examples/blog/src/views/blog_entry_email.xhtml +16 -0
  49. data/examples/blog/{root → src/views}/comments.xhtml +0 -0
  50. data/examples/blog/{root → src/views}/entry_form.xhtml +0 -0
  51. data/examples/blog/{root → src/views}/error.xhtml +0 -0
  52. data/examples/blog/{root → src/views}/index.xhtml +0 -0
  53. data/examples/blog/{root → src/views}/login.xhtml +0 -0
  54. data/examples/blog/{root → src/views}/recent_posts.xhtml +0 -0
  55. data/examples/blog/{root → src/views}/view_entry.xhtml +8 -0
  56. data/examples/blog/{root → src/views}/view_entry.xml +0 -0
  57. data/examples/blog/src/xsl/base.xsl +153 -0
  58. data/examples/blog/{root → src/xsl}/style.xsl +2 -2
  59. data/examples/no_xsl_blog/README +5 -1
  60. data/examples/no_xsl_blog/conf/apache.conf +2 -2
  61. data/examples/no_xsl_blog/conf/lhttpd.conf +2 -2
  62. data/examples/no_xsl_blog/lib/blog/model.rb +1 -1
  63. data/{lib/parts → examples/no_xsl_blog/lib}/content.rb +1 -11
  64. data/examples/no_xsl_blog/log/apache.error_log +405 -0
  65. data/examples/no_xsl_blog/{root → public}/comments.xhtml +0 -0
  66. data/examples/no_xsl_blog/{root → public}/entry_form.xhtml +0 -0
  67. data/examples/no_xsl_blog/{root → public}/fcgi.rb +0 -0
  68. data/examples/no_xsl_blog/{root → public}/index.xhtml +0 -0
  69. data/examples/no_xsl_blog/{root → public}/login.xhtml +0 -0
  70. data/examples/no_xsl_blog/{root → public}/m/bubbles.gif +0 -0
  71. data/examples/no_xsl_blog/{root → public}/m/comments_curve.gif +0 -0
  72. data/examples/no_xsl_blog/{root → public}/m/down.gif +0 -0
  73. data/examples/no_xsl_blog/{root → public}/m/footer_bg.gif +0 -0
  74. data/examples/no_xsl_blog/{root → public}/m/garrow.gif +0 -0
  75. data/examples/no_xsl_blog/{root → public}/m/gbull.gif +0 -0
  76. data/examples/no_xsl_blog/{root → public}/m/grbull.gif +0 -0
  77. data/examples/no_xsl_blog/{root → public}/m/h1_bg.gif +0 -0
  78. data/examples/no_xsl_blog/{root → public}/m/header_bg.gif +0 -0
  79. data/examples/no_xsl_blog/{root → public}/m/nitro.gif +0 -0
  80. data/examples/no_xsl_blog/{root → public}/m/obull.gif +0 -0
  81. data/examples/no_xsl_blog/{root → public}/m/page_bg.gif +0 -0
  82. data/examples/no_xsl_blog/{root → public}/m/rss.gif +0 -0
  83. data/examples/no_xsl_blog/{root → public}/m/side_title_bg.gif +0 -0
  84. data/examples/no_xsl_blog/{root → public}/m/sidebar_bg.gif +0 -0
  85. data/examples/no_xsl_blog/{root → public}/recent_posts.xhtml +0 -0
  86. data/examples/{blog/root → no_xsl_blog/public}/style.css +0 -0
  87. data/examples/no_xsl_blog/{root → public}/view_entry.xhtml +0 -0
  88. data/examples/no_xsl_blog/{root → public}/view_entry.xml +0 -0
  89. data/examples/tiny/conf/apache.conf +2 -2
  90. data/examples/tiny/log/apache.error_log +100 -0
  91. data/examples/tiny/{root → public}/fcgi.rb +0 -0
  92. data/examples/tiny/{root → public}/include.xhtml +0 -0
  93. data/examples/tiny/{root → public}/index.xhtml +0 -0
  94. data/{bin/proto/root/m → examples/tiny/public}/nitro.png +0 -0
  95. data/examples/tiny/{root → public}/upload.xhtml +0 -0
  96. data/examples/tiny/run.rb +1 -2
  97. data/examples/why_wiki/wiki.yml +1 -0
  98. data/install.rb +5 -2
  99. data/lib/nitro.rb +2 -6
  100. data/lib/nitro/adapters/fastcgi.rb +2 -2
  101. data/lib/nitro/adapters/webrick.rb +4 -4
  102. data/lib/nitro/conf.rb +5 -2
  103. data/lib/nitro/controller.rb +2 -2
  104. data/lib/nitro/dispatcher.rb +19 -8
  105. data/lib/nitro/mail.rb +252 -8
  106. data/lib/nitro/render.rb +24 -21
  107. data/lib/nitro/runner.rb +1 -1
  108. data/lib/nitro/scaffold.rb +2 -5
  109. data/lib/nitro/simple.rb +2 -1
  110. data/lib/nitro/template.rb +42 -2
  111. data/test/nitro/tc_controller.rb +9 -4
  112. data/test/nitro/tc_dispatcher.rb +4 -6
  113. data/test/nitro/tc_mail.rb +95 -0
  114. data/test/{root → public}/blog/list.xhtml +0 -0
  115. data/test/public/dummy_mailer/registration.xhtml +5 -0
  116. data/vendor/README +0 -1
  117. metadata +136 -181
  118. data/benchmark/og/bench.rb +0 -75
  119. data/benchmark/og/sqlite-no-prepare.1.txt +0 -13
  120. data/benchmark/og/sqlite-no-prepare.2.txt +0 -13
  121. data/benchmark/og/sqlite-prepare.1.txt +0 -13
  122. data/benchmark/og/sqlite-prepare.2.txt +0 -13
  123. data/bin/proto/README +0 -34
  124. data/bin/proto/conf/apache.conf +0 -1
  125. data/bin/proto/conf/app.conf.rb +0 -14
  126. data/bin/proto/conf/lhttpd.conf +0 -236
  127. data/bin/proto/ctl +0 -4
  128. data/bin/proto/lib/README +0 -5
  129. data/bin/proto/log/README +0 -3
  130. data/bin/proto/root/fcgi.rb +0 -6
  131. data/bin/proto/root/index.xhtml +0 -69
  132. data/bin/proto/root/style.css +0 -152
  133. data/bin/proto/root/style.xsl +0 -99
  134. data/doc/og_config.txt +0 -35
  135. data/doc/og_tutorial.txt +0 -595
  136. data/examples/og/README +0 -11
  137. data/examples/og/mock_example.rb +0 -50
  138. data/examples/og/mysql_to_psql.rb +0 -96
  139. data/examples/og/run.rb +0 -286
  140. data/examples/tiny/root/nitro.png +0 -0
  141. data/lib/glue.rb +0 -55
  142. data/lib/glue/array.rb +0 -61
  143. data/lib/glue/attribute.rb +0 -83
  144. data/lib/glue/cache.rb +0 -138
  145. data/lib/glue/flexob.rb +0 -12
  146. data/lib/glue/hash.rb +0 -122
  147. data/lib/glue/inflector.rb +0 -91
  148. data/lib/glue/logger.rb +0 -147
  149. data/lib/glue/misc.rb +0 -14
  150. data/lib/glue/mixins.rb +0 -36
  151. data/lib/glue/number.rb +0 -24
  152. data/lib/glue/object.rb +0 -32
  153. data/lib/glue/pool.rb +0 -60
  154. data/lib/glue/property.rb +0 -408
  155. data/lib/glue/string.rb +0 -162
  156. data/lib/glue/time.rb +0 -85
  157. data/lib/glue/validation.rb +0 -394
  158. data/lib/og.rb +0 -185
  159. data/lib/og/adapter.rb +0 -513
  160. data/lib/og/adapters/filesys.rb +0 -121
  161. data/lib/og/adapters/mysql.rb +0 -347
  162. data/lib/og/adapters/oracle.rb +0 -375
  163. data/lib/og/adapters/psql.rb +0 -273
  164. data/lib/og/adapters/sqlite.rb +0 -262
  165. data/lib/og/backend.rb +0 -297
  166. data/lib/og/connection.rb +0 -304
  167. data/lib/og/database.rb +0 -282
  168. data/lib/og/enchant.rb +0 -125
  169. data/lib/og/meta.rb +0 -373
  170. data/lib/og/mock.rb +0 -165
  171. data/lib/og/observer.rb +0 -53
  172. data/lib/og/typemacros.rb +0 -23
  173. data/lib/parts/README +0 -9
  174. data/test/glue/tc_attribute.rb +0 -22
  175. data/test/glue/tc_cache.rb +0 -45
  176. data/test/glue/tc_hash.rb +0 -38
  177. data/test/glue/tc_logger.rb +0 -39
  178. data/test/glue/tc_numbers.rb +0 -20
  179. data/test/glue/tc_property.rb +0 -89
  180. data/test/glue/tc_property_mixins.rb +0 -93
  181. data/test/glue/tc_property_type_checking.rb +0 -35
  182. data/test/glue/tc_strings.rb +0 -103
  183. data/test/glue/tc_validation.rb +0 -188
  184. data/test/og/tc_filesys.rb +0 -83
  185. data/test/og/tc_lifecycle.rb +0 -104
  186. data/test/og/tc_many_to_many.rb +0 -62
  187. data/test/og/tc_meta.rb +0 -55
  188. data/test/og/tc_observer.rb +0 -85
  189. data/test/og/tc_sqlite.rb +0 -87
  190. data/test/tc_og.rb +0 -355
  191. data/vendor/composite_sexp_processor.rb +0 -43
  192. data/vendor/parse_tree.rb +0 -745
  193. data/vendor/sexp_processor.rb +0 -453
data/lib/og.rb DELETED
@@ -1,185 +0,0 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: og.rb 270 2005-03-07 17:52:16Z gmosx $
4
-
5
- require 'glue'
6
- require 'glue/logger'
7
- require 'glue/attribute'
8
- require 'glue/property'
9
- require 'glue/array'
10
- require 'glue/hash'
11
- require 'glue/time'
12
- require 'glue/pool'
13
- require 'glue/validation'
14
-
15
- # Og (ObjectGraph) is an efficient, yet simple Object-Relational
16
- # mapping library.
17
- #
18
- # === Features
19
- #
20
- # The library provides the following features:
21
- #
22
- # + Object-Relational mapping.
23
- # + Absolutely no configuration files.
24
- # + Multiple backends (PostgreSQL, MySQL, SQLite).
25
- # + ActiveRecord-style meta language and db aware methods.
26
- # + Deserialize to Ruby Objects.
27
- # + Deserialize sql join queries to Ruby Objects (temporarily dissabled).
28
- # + Serialize arbitrary ruby object graphs through YAML.
29
- # + Connection pooling.
30
- # + Thread safety.
31
- # + SQL transactions.
32
- # + Lifecycle callbacks.
33
- # + Lifecycle observers.
34
- # + Transparent support for cascading deletes for all backends.
35
- # + Hierarchical structures (preorder traversal, materialized paths)
36
- # + Works safely as part of distributed application.
37
- # + Simple implementation.
38
- #
39
- # === Meta language
40
- #
41
- # primary_key :pid (NOT IMPLEMENTED)
42
- # name_key :name (NOT IMPLEMENTED)
43
- # prop_accessor Fixnum, :pid, :sql => "smallint DEFAULT 1"
44
- # has_many Child, :children
45
- # many_to_many Role, :roles
46
- # sql_index :pid
47
- #
48
- # === Property Metadata
49
- #
50
- # Og defines, reserves and uses the following property
51
- # metadata types:
52
- #
53
- # [+:sql_index+]
54
- # Create an sql index for this property.
55
- #
56
- # [+:unique+]
57
- # This value of the property must be unique.
58
- #
59
- # [+:name_key+]
60
- # This property is used as name-key.
61
- #
62
- # === Design
63
- #
64
- # Keep the main classes backend agnostic.
65
- #
66
- # For class ids we use the name instead of a hash. Class ids are
67
- # typically not used in querys, they are stored for completeness.
68
- # If we store a hash we cannot reclaim the class thus invalidating
69
- # the point. Instead of .name(), to_s() is used so the methods
70
- # are more flexible (they accept class names too!!)
71
- #
72
- # Og allows the serialization of arbitrary Ruby objects. Just
73
- # mark them as Object (or Array or Hash) in the prop_accessor
74
- # and the engine will serialize a YAML dump of the object.
75
- # Arbitrary object graphs are supported too.
76
- #
77
- # This is NOT a singleton, an application may access multiple
78
- # databases.
79
- #
80
- # The og.xxx methods are more flexible and allow you to use
81
- # multiple databases for example.
82
- #
83
- # === Managed Objects Lifecycle Callbacks
84
- #
85
- # * og_pre_read
86
- # * og_post_read
87
- # * og_pre_insert
88
- # * og_post_insert
89
- # * og_pre_update
90
- # * og_post_update
91
- # * og_pre_insert_update
92
- # * og_post_insert_update
93
- # * self.og_pre_delete
94
- #
95
- # A class level callback is used for delete because typically you call
96
- # delete with an oid and not an object to avoid a deserialization.
97
- #
98
- # === Future
99
- #
100
- # * Support prepared statements (pgsql)
101
- # * Support stored procedures (pgsql)
102
- # * Support caching.
103
- # * Deserialize to OpenStruct.
104
- # * Better documentation.
105
-
106
- module Og
107
-
108
- # The name.
109
-
110
- Name = 'ObjectGraph'
111
-
112
- # The version.
113
-
114
- Version = '0.12.0'
115
-
116
- # Library path.
117
-
118
- LibPath = File.dirname(__FILE__)
119
-
120
- # If true, only allow reading from the database. Usefull
121
- # for maintainance.
122
-
123
- mattr_accessor :read_only_mode, false
124
-
125
- # If true, the library automatically 'enchants' managed classes.
126
- # In enchant mode, special db aware methods are added to
127
- # managed classes and instances.
128
- # If false, Og enchants only classes that define properties.
129
-
130
- mattr_accessor :enchant_managed_classes, true
131
-
132
- # If true, use Ruby's advanced introspection capabilities to
133
- # automatically manage classes tha define properties.
134
-
135
- mattr_accessor :auto_manage_classes, true
136
-
137
- # If true, automatically include the Og meta-language into Module.
138
- # If false, the polution of the Module object is avoided. However
139
- # if you include a prop_accessor or a managed Mixin in your
140
- # object MetaLanguage gets automatically extended in the class.
141
-
142
- mattr_accessor :include_meta_language, true
143
-
144
- # Attach the following prefix to all generated SQL table names.
145
- # Usefull on hosting scenarios where you have to run multiple
146
- # web applications/sites on a single database.
147
-
148
- mattr_accessor :table_prefix, nil
149
-
150
- # If true, Og tries to create/update the schema in the
151
- # data store. For production/live environments set this to false
152
- # and only set to true when the object model is upadated.
153
- # For debug/development environments this should stay true
154
- # for convienience.
155
-
156
- mattr_accessor :create_schema, true
157
-
158
- # The active database. Og allows you to access multiple
159
- # databases from a single application.
160
-
161
- mattr_accessor :db
162
-
163
- # Set the active database.
164
-
165
- def self.use(db)
166
- @@db = db
167
- @@db.get_connection
168
- end
169
-
170
- # The adapter of the active database.
171
-
172
- def self.adapter
173
- @@db.adapter
174
- end
175
-
176
- # Marker module. If included this in a class, the Og automanager
177
- # ignores this class.
178
-
179
- module Unmanageable; end
180
-
181
- end
182
-
183
- # gmosx: leave this here.
184
-
185
- require 'og/database'
data/lib/og/adapter.rb DELETED
@@ -1,513 +0,0 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: adapter.rb 270 2005-03-07 17:52:16Z gmosx $
4
-
5
- require 'yaml'
6
- require 'singleton'
7
-
8
- require 'og/connection'
9
-
10
- module Og
11
-
12
- # An adapter communicates with the backend datastore.
13
- # The adapters for all supported datastores extend this
14
- # class. Typically, an RDBMS is used to implement a
15
- # datastore.
16
-
17
- class Adapter
18
- include Singleton
19
-
20
- # A mapping between Ruby and backend Datastore types.
21
-
22
- attr_accessor :typemap
23
-
24
- # A map for casting Ruby types to SQL safe textual
25
- # representations.
26
-
27
- attr_accessor :typecast
28
-
29
- # Lookup the adapter instance from the adapter name.
30
-
31
- def self.for_name(name)
32
- require "og/adapters/#{name}"
33
- eval %{ return #{name.capitalize}Adapter.instance }
34
- end
35
-
36
- def initialize
37
- # The default mappings, should be valid for most
38
- # RDBMS.
39
-
40
- @typemap = {
41
- Integer => 'integer',
42
- Fixnum => 'integer',
43
- Float => 'float',
44
- String => 'text',
45
- Time => 'timestamp',
46
- Date => 'date',
47
- TrueClass => 'boolean',
48
- Object => 'text',
49
- Array => 'text',
50
- Hash => 'text'
51
- }
52
-
53
- # The :s: is a marker that will be replaced with the
54
- # actual value to be casted. The default parameter of
55
- # the Hash handles all other types (Object, Array, etc)
56
-
57
- @typecast = Hash.new("'#\{#{self.class}.escape(:s:.to_yaml)\}'").update(
58
- Integer => "\#\{:s:\}",
59
- Float => "\#\{:s:\}",
60
- String => "'#\{#{self.class}.escape(:s:)\}'",
61
- Time => "'#\{#{self.class}.timestamp(:s:)\}'",
62
- Date => "'#\{#{self.class}.date(:s:)\}'",
63
- TrueClass => "#\{:s: ? \"'t'\" : 'NULL' \}"
64
- )
65
- end
66
-
67
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
68
- # :section: Utilities
69
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
70
-
71
- # Escape an SQL string
72
-
73
- def self.escape(str)
74
- return nil unless str
75
- return str.gsub( /'/, "''" )
76
- end
77
-
78
- # Convert a ruby time to an sql timestamp.
79
- # TODO: Optimize this
80
-
81
- def self.timestamp(time = Time.now)
82
- return nil unless time
83
- return time.strftime("%Y-%m-%d %H:%M:%S")
84
- end
85
-
86
- # Output YYY-mm-dd
87
- # TODO: Optimize this
88
-
89
- def self.date(date)
90
- return nil unless date
91
- return "#{date.year}-#{date.month}-#{date.mday}"
92
- end
93
-
94
- # Parse sql datetime
95
- # TODO: Optimize this
96
-
97
- def self.parse_timestamp(str)
98
- return nil unless str
99
- return Time.parse(str)
100
- end
101
-
102
- # Input YYYY-mm-dd
103
- # TODO: Optimize this
104
-
105
- def self.parse_date(str)
106
- return nil unless str
107
- return Date.strptime(str)
108
- end
109
-
110
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
111
- # :section: Database methods
112
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
113
-
114
- # Create the database.
115
-
116
- def create_db(database, user = nil, password = nil)
117
- Logger.info "Creating database '#{database}'."
118
- end
119
-
120
- # Drop the database.
121
-
122
- def drop_db(database, user = nil, password = nil)
123
- Logger.info "Dropping database '#{database}'."
124
- end
125
-
126
- # Create a new connection to the backend.
127
-
128
- def new_connection(db)
129
- return Connection.new(db)
130
- end
131
-
132
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
133
- # :section: O->R mapping methods and utilities.
134
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
135
-
136
- # Encode the name of the klass as an sql safe string.
137
- # The Module separators are replaced with _ and NOT stripped
138
- # out so that we can convert back to the original notation if
139
- # needed. The leading module if available is removed.
140
-
141
- def self.encode(klass)
142
- "#{klass.name.gsub(/^.*::/, "")}".gsub(/::/, "_").downcase
143
- end
144
-
145
- # The name of the SQL table where objects of this class
146
- # are stored. A prefix is needed to avoid colision with
147
- # reserved prefices (for example User maps to user which
148
- # is reserved in postgresql). The prefix should start
149
- # with an alphanumeric character to be compatible with
150
- # all RDBMS (most notable Oracle).
151
- #
152
- # You may want to override this method to map an existing
153
- # database schema using Og.
154
-
155
- def self.table(klass)
156
- "og_#{Og.table_prefix}#{encode(klass)}"
157
- end
158
-
159
- # The name of the join table for the two given classes.
160
- # A prefix is needed to avoid colision with reserved
161
- # prefices (for example User maps to user which
162
- # is reserved in postgresql). The prefix should start
163
- # with an alphanumeric character to be compatible with
164
- # all RDBMS (most notable Oracle).
165
- #
166
- # You may want to override this method to map an existing
167
- # database schema using Og.
168
-
169
- def self.join_table(klass1, klass2, field)
170
- "og_#{Og.table_prefix}j_#{encode(klass1)}_#{encode(klass2)}_#{field}"
171
- end
172
-
173
- # Return an sql string evaluator for the property.
174
- # No need to optimize this, used only to precalculate code.
175
- # YAML is used to store general Ruby objects to be more
176
- # portable.
177
- #--
178
- # FIXME: add extra handling for float.
179
- #++
180
-
181
- def write_prop(p)
182
- if p.klass.ancestors.include?(Integer)
183
- return "#\{@#{p.symbol} || 'NULL'\}"
184
- elsif p.klass.ancestors.include?(Float)
185
- return "#\{@#{p.symbol} || 'NULL'\}"
186
- elsif p.klass.ancestors.include?(String)
187
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol})\}'" : 'NULL'\}|
188
- elsif p.klass.ancestors.include?(Time)
189
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
190
- elsif p.klass.ancestors.include?(Date)
191
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}|
192
- elsif p.klass.ancestors.include?(TrueClass)
193
- return "#\{@#{p.symbol} ? \"'t'\" : 'NULL' \}"
194
- else
195
- # gmosx: keep the '' for nil symbols.
196
- return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
197
- end
198
- end
199
-
200
- # Return an evaluator for reading the property.
201
- # No need to optimize this, used only to precalculate code.
202
-
203
- def read_prop(p, idx)
204
- if p.klass.ancestors.include?(Integer)
205
- return "res[#{idx}].to_i"
206
- elsif p.klass.ancestors.include?(Float)
207
- return "res[#{idx}].to_f"
208
- elsif p.klass.ancestors.include?(String)
209
- return "res[#{idx}]"
210
- elsif p.klass.ancestors.include?(Time)
211
- return "#{self.class}.parse_timestamp(res[#{idx}])"
212
- elsif p.klass.ancestors.include?(Date)
213
- return "#{self.class}.parse_date(res[#{idx}])"
214
- elsif p.klass.ancestors.include?(TrueClass)
215
- return "('0' != res[#{idx}])"
216
- else
217
- return "YAML::load(res[#{idx}])"
218
- end
219
- end
220
-
221
- # Create the fields that correpsond to the klass properties.
222
- # The generated fields array is used in create_table.
223
- # If the property has an :sql metadata this overrides the
224
- # default mapping. If the property has an :extra_sql metadata
225
- # the extra sql is appended after the default mapping.
226
-
227
- def create_fields(klass)
228
- fields = []
229
-
230
- klass.__props.each do |p|
231
- klass.sql_index(p.symbol) if p.meta[:sql_index]
232
-
233
- field = "#{p.symbol}"
234
-
235
- if p.meta and p.meta[:sql]
236
- field << " #{p.meta[:sql]}"
237
- else
238
- field << " #{@typemap[p.klass]}"
239
-
240
- if p.meta
241
- # set default value (gmosx: not that useful in the
242
- # current implementation).
243
- if default = p.meta[:default]
244
- field << " DEFAULT #{default.inspect} NOT NULL"
245
- end
246
-
247
- # set unique
248
- field << " UNIQUE" if p.meta[:unique]
249
-
250
- # attach extra sql
251
- if extra_sql = p.meta[:extra_sql]
252
- field << " #{extra_sql}"
253
- end
254
- end
255
- end
256
-
257
- fields << field
258
- end
259
-
260
- return fields
261
- end
262
-
263
- # Create the managed object table. The properties of the
264
- # object are mapped to the table columns. Additional sql relations
265
- # and constrains are created (indicices, sequences, etc).
266
-
267
- def create_table(klass)
268
- raise 'Not implemented!'
269
- end
270
-
271
- # Returns the props that will be included in the insert query.
272
- # For some backends the oid should be stripped.
273
-
274
- def props_for_insert(klass)
275
- klass.__props
276
- end
277
-
278
- # Returns the code that actually inserts the object into the
279
- # database. Returns the code as String.
280
-
281
- def insert_code(klass, sql, pre_cb, post_cb)
282
- raise 'Not implemented!'
283
- end
284
-
285
- # Generate the mapping of the database fields to the
286
- # object properties.
287
-
288
- def calc_field_index(klass, og)
289
- # Implement if needed.
290
- end
291
-
292
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
293
- # :section: Precompile lifecycle methods.
294
- # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
295
-
296
- # Precompile some code that gets executed all the time.
297
- # Deletion code is not precompiled, because it is not used
298
- # as frequently.
299
-
300
- def eval_lifecycle_methods(klass, db)
301
- eval_og_insert(klass, db)
302
- eval_og_update(klass, db)
303
- eval_og_read(klass, db)
304
- end
305
-
306
- # Generate the property for oid.
307
-
308
- def eval_og_oid(klass)
309
- klass.class_eval %{
310
- prop_accessor :oid, Fixnum, :sql => "integer PRIMARY KEY"
311
- }
312
- end
313
-
314
- # Precompile the insert code for the given class.
315
- # The generated code sets the oid when inserting!
316
-
317
- def eval_og_insert(klass, db)
318
-
319
- # Attach object callbacks.
320
-
321
- if klass.instance_methods.include?('og_pre_insert')
322
- pre_cb = 'og_pre_insert(conn);'
323
- else
324
- pre_cb = ''
325
- end
326
-
327
- if klass.instance_methods.include?('og_post_insert')
328
- post_cb = 'og_post_insert(conn);'
329
- else
330
- post_cb = ''
331
- end
332
-
333
- if klass.instance_methods.include?('og_pre_insert_update')
334
- pre_cb << 'og_pre_insert_update(conn);'
335
- end
336
-
337
- if klass.instance_methods.include?('og_post_insert_update')
338
- post_cb << 'og_post_insert_update(conn);'
339
- end
340
-
341
- # Attach observers.
342
-
343
- if observers = klass.__meta[:og_observers]
344
- observers.each_with_index do |o, idx|
345
- if o.is_a?(Class)
346
- obs = "#{o}.instance"
347
- o = o.instance
348
- else
349
- obs = "self.class.__meta[:og_observers][#{idx}]"
350
- end
351
-
352
- if o.respond_to?(:og_pre_insert)
353
- pre_cb << "#{obs}.og_pre_insert(conn, self);"
354
- end
355
-
356
- if o.respond_to?(:og_post_insert)
357
- post_cb << "#{obs}.og_post_insert(conn, self);"
358
- end
359
-
360
- if o.respond_to?(:og_pre_insert_update)
361
- pre_cb << "#{obs}.og_pre_insert_update(conn, self);"
362
- end
363
-
364
- if o.respond_to?(:og_post_insert_update)
365
- post_cb << "#{obs}.og_post_insert_update(conn, self);"
366
- end
367
- end
368
- end
369
-
370
- klass.class_eval %{
371
- def og_insert(conn)
372
- #{insert_code(klass, db, pre_cb, post_cb)}
373
- end
374
- }
375
- end
376
-
377
- # Precompile the update code for the given class.
378
- # Ignore the oid when updating!
379
-
380
- def eval_og_update(klass, db)
381
- props = klass.__props.reject { |p| :oid == p.symbol }
382
-
383
- updates = props.collect { |p|
384
- "#{p.name}=#{write_prop(p)}"
385
- }
386
-
387
- sql = "UPDATE #{klass::DBTABLE} SET #{updates.join(', ')} WHERE oid=#\{@oid\}"
388
-
389
- # Attach object callbacks.
390
-
391
- if klass.instance_methods.include?('og_pre_update')
392
- pre_cb = 'og_pre_update(conn);'
393
- else
394
- pre_cb = ''
395
- end
396
-
397
- if klass.instance_methods.include?('og_post_update')
398
- post_cb = 'og_post_update(conn);'
399
- else
400
- post_cb = ''
401
- end
402
-
403
- if klass.instance_methods.include?('og_pre_insert_update')
404
- pre_cb << 'og_pre_insert_update(conn);'
405
- end
406
-
407
- if klass.instance_methods.include?('og_post_insert_update')
408
- post_cb << 'og_post_insert_update(conn);'
409
- end
410
-
411
- # Attach observers.
412
-
413
- if observers = klass.__meta[:og_observers]
414
- observers.each_with_index do |o, idx|
415
- if o.is_a?(Class)
416
- obs = "#{o}.instance"
417
- o = o.instance
418
- else
419
- obs = "self.class.__meta[:og_observers][#{idx}]"
420
- end
421
-
422
- if o.respond_to?(:og_pre_update)
423
- pre_cb << "#{obs}.og_pre_update(conn, self);"
424
- end
425
-
426
- if o.respond_to?(:og_post_update)
427
- post_cb << "#{obs}.og_post_update(conn, self);"
428
- end
429
-
430
- if o.respond_to?(:og_pre_insert_update)
431
- pre_cb << "#{obs}.og_pre_insert_update(conn, self);"
432
- end
433
-
434
- if o.respond_to?(:og_post_insert_update)
435
- post_cb << "#{obs}.og_post_insert_update(conn, self);"
436
- end
437
- end
438
- end
439
-
440
- klass.class_eval %{
441
- def og_update(conn)
442
- #{pre_cb}
443
- conn.exec "#{sql}"
444
- #{post_cb}
445
- end
446
- }
447
- end
448
-
449
- # Precompile the code to read (deserialize) objects of the
450
- # given class from the backend. In order to allow for changing
451
- # field/attribute orders we have to use a field mapping hash.
452
-
453
- def eval_og_read(klass, db)
454
- calc_field_index(klass, db)
455
-
456
- props = klass.__props
457
- code = []
458
-
459
- props.each do |p|
460
- if idx = db.managed_classes[klass].field_index[p.name]
461
- # more fault tolerant if a new field is added and it
462
- # doesnt exist in the database.
463
- code << "@#{p.name} = #{read_prop(p, idx)}"
464
- end
465
- end
466
-
467
- # Attach object callbacks.
468
-
469
- if klass.instance_methods.include?('og_pre_read')
470
- pre_cb = 'og_pre_read(conn);'
471
- else
472
- pre_cb = ''
473
- end
474
-
475
- if klass.instance_methods.include?('og_post_read')
476
- post_cb = 'og_post_read(conn);'
477
- else
478
- post_cb = ''
479
- end
480
-
481
- # Attach observers.
482
-
483
- if observers = klass.__meta[:og_observers]
484
- observers.each_with_index do |o, idx|
485
- if o.is_a?(Class)
486
- obs = "#{o}.instance"
487
- o = o.instance
488
- else
489
- obs = "self.class.__meta[:og_observers][#{idx}]"
490
- end
491
-
492
- if o.respond_to?(:og_pre_read)
493
- pre_cb << "#{obs}.og_pre_read(conn, self);"
494
- end
495
-
496
- if o.respond_to?(:og_post_read)
497
- post_cb << "#{obs}.og_post_read(conn, self);"
498
- end
499
- end
500
- end
501
-
502
- klass.class_eval %{
503
- def og_read(res, tuple = nil)
504
- #{pre_cb}
505
- #{code.join('; ')}
506
- #{post_cb}
507
- end
508
- }
509
- end
510
-
511
- end
512
-
513
- end