nitro 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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/examples/og/README DELETED
@@ -1,11 +0,0 @@
1
- = Og Example
2
-
3
- == run.rb
4
-
5
- A simple example that demonstrates some Og features. The example
6
- automatically creates a 'test' database.
7
-
8
- == mock_example.rb
9
-
10
- Demonstrates how easily the Og infrastructure can be mocked,
11
- for easy test unit writing.
@@ -1,50 +0,0 @@
1
- # = Og Mocking Example
2
- #
3
- # A simple example to demonstrate how to mock Og.
4
- # Very useful in test units.
5
- #
6
- # * George Moschovitis <gm@navel.gr>
7
- # (c) 2004-2005 Navel, all rights reserved.
8
- # $Id: run.rb 185 2004-12-10 13:29:09Z gmosx $
9
-
10
- require 'rubygems'
11
- require 'flexmock'
12
- require 'og'
13
- require 'og/mock'
14
-
15
- class Article
16
- prop_accessor :body, String
17
-
18
- def initialize(body = nil)
19
- @body = body
20
- end
21
- end
22
-
23
- class SimpleTest < Test::Unit::TestCase
24
-
25
- def setup
26
- @og = Og::MockDatabase.new
27
- end
28
-
29
- def teardown
30
- @og = nil
31
- end
32
-
33
- def test_me
34
- mocks = [
35
- Article.new('body1'),
36
- Article.new('body2'),
37
- Article.new('body3')
38
- ]
39
- @og.mock_handle(:load_all) { |klass, extrasql| mocks }
40
-
41
- # differnt ways to call the mocked method...
42
- puts 'Here are the articles:', Article.all
43
- puts 'Here are the articles:', Article.load_all
44
- puts 'Here are the articles:', @og.load_all(Article)
45
-
46
- # 3 times called
47
- assert_equal(3, @og.mock_count(:load_all))
48
- end
49
-
50
- end
@@ -1,96 +0,0 @@
1
- # = Og Mysql to PostgreSQL copy example
2
- #
3
- # A simple example to demonstrate the flexibility of
4
- # Og. Two connections to different databases are
5
- # created and data is copied from a MySQL database
6
- # to a PostgreSQL database.
7
- #
8
- # Og makes it easier to switch to a REAL database :)
9
- #
10
- # * George Moschovitis <gm@navel.gr>
11
- # (c) 2004-2005 Navel, all rights reserved.
12
- # $Id$
13
-
14
- raise 'WARNING, this example does not work yet, for the moment ' +
15
- 'just have a look at the source code.'
16
-
17
- require 'og'
18
-
19
- # An example managed object.
20
- # Looks like an ordinary Ruby object.
21
-
22
- class Article
23
- prop_accessor :name, :body, String
24
-
25
- def initialize(name = nil, body = nil)
26
- @name, @body = name, body
27
- end
28
- end
29
-
30
- # Configure databases.
31
-
32
- psql_config = {
33
- :address => 'localhost',
34
- :database => 'test',
35
- :backend => 'psql',
36
- :user => 'postgres',
37
- :password => 'navelrulez',
38
- :connection_count => 1
39
- }
40
-
41
- mysql_config = {
42
- :address => 'localhost',
43
- :database => 'mysql',
44
- :backend => 'psql',
45
- :user => 'postgres',
46
- :password => 'navelrulez',
47
- :connection_count => 1
48
- }
49
- =begin
50
- mysql_config = {
51
- :address => 'localhost',
52
- :database => 'test',
53
- :backend => 'mysql',
54
- :user => 'root',
55
- :password => 'navelrulez',
56
- :connection_count => 1
57
- }
58
- =end
59
-
60
- # Cleanup the databases, remove data from
61
- # earlier executions.
62
-
63
- Og::Database.drop!(psql_config)
64
- Og::Database.drop!(mysql_config)
65
-
66
- # Initialize Og.
67
-
68
- psql = Og::Database.new(psql_config)
69
- mysql = Og::Database.new(mysql_config)
70
-
71
- # First populate the mysql database.
72
-
73
- Og.use(mysql)
74
-
75
- a1 = Article.create('name1', 'body1')
76
- a1 = Article.create('name1', 'body1')
77
- a1 = Article.create('name1', 'body1')
78
-
79
- # Read all articles from Mysql.
80
-
81
- articles = Article.all
82
-
83
- # Switch to PostgreSQL.
84
-
85
- Og.use(psql)
86
-
87
- # Store all articles.
88
-
89
- for article in articles
90
- article.save!
91
- end
92
-
93
- # Fetch an article from PostgreSQL
94
- # as an example. Lookup by name.
95
-
96
- article = Article['name1']
data/examples/og/run.rb DELETED
@@ -1,286 +0,0 @@
1
- # A simple example to demonstrate the Og library.
2
- #
3
- # * George Moschovitis <gm@navel.gr>
4
- # (c) 2004 Navel, all rights reserved.
5
- # $Id: run.rb 263 2005-02-23 13:45:08Z gmosx $
6
-
7
- require 'og'
8
-
9
- # Full debug information.
10
-
11
- $DBG = true
12
-
13
- # A child class.
14
-
15
- class Comment
16
- prop_accessor :body, String
17
-
18
- def initialize(body = nil)
19
- @body = body
20
- end
21
-
22
- def to_s
23
- return @body
24
- end
25
- end
26
-
27
- # forward declaration
28
- class ArticleComment < Comment; end
29
-
30
- # forward declaration
31
- class UserComment < Comment; end
32
-
33
- # forward declaration
34
- class Part; end
35
-
36
- # = A Parent class
37
- #
38
- class User
39
- prop_accessor :name, String
40
-
41
- has_many :comments, UserComment
42
-
43
- def initialize(name = nil)
44
- @name = name
45
- end
46
-
47
- def to_s
48
- return @name
49
- end
50
- end
51
-
52
-
53
- # A parent class.
54
-
55
- class Article
56
- prop_accessor :title, String
57
- prop_accessor :body, String
58
- # override the default O->R mapping
59
- prop_accessor :level, Fixnum, :sql => "smallint DEFAULT 1"
60
- # store a Ruby Hash in the Database. YAML
61
- # is used for serializing the attribute.
62
- # no need to define the class, but you can if you want.
63
- prop_accessor :options
64
- # exactly like the standard Ruby attr creates only the reader.
65
- prop :create_time, Time
66
-
67
- # define comment relation:
68
- has_many :comments, ArticleComment
69
-
70
- has_many :parts, Part
71
-
72
- # define author relation:
73
- belongs_to :author, User
74
-
75
- # this attribute is NOT stored in the db.
76
- attr_accessor :other_options
77
-
78
- # Managed object constructors with no args, take *args
79
- # as parameter to allow for Mixin chaining.
80
- #
81
- def initialize(title = nil, body = nil)
82
- @title, @body = title, body
83
- @create_time = Time.now
84
- @options = {}
85
- @other_options = {}
86
- end
87
-
88
- def to_s
89
- return "#@title: #@body"
90
- end
91
- end
92
-
93
- # A parent class.
94
-
95
- class Category
96
- prop_accessor :title, String
97
- prop_accessor :body, String
98
-
99
- # define a 'many to many' relation.
100
- many_to_many :articles, Article
101
-
102
- def initialize(title = nil)
103
- @title = title
104
- end
105
- end
106
-
107
-
108
- # Article comment.
109
-
110
- class ArticleComment < Comment
111
- belongs_to :article, Article
112
- end
113
-
114
- # User comment.
115
-
116
- class UserComment < Comment
117
- belongs_to :author, User
118
- end
119
-
120
- # Another child class.
121
-
122
- class Part
123
- prop_accessor :name, String
124
- belongs_to :article, Article
125
-
126
- def initialize(name = nil)
127
- @name = name
128
- end
129
-
130
- def to_s
131
- return @name
132
- end
133
- end
134
-
135
- # Og configuration.
136
- config = {
137
- :database => "test",
138
- :adapter => "sqlite",
139
- :connection_count => 2
140
- }
141
- =begin
142
- config = {
143
- # :address => "localhost",
144
- :database => "test",
145
- :adapter => "psql",
146
- :user => "postgres",
147
- :password => "navelrulez",
148
- :connection_count => 1
149
- }
150
-
151
- config = {
152
- :address => "localhost",
153
- :database => "test",
154
- :backend => "mysql",
155
- :user => "root",
156
- :password => "navelrulez",
157
- :connection_count => 1
158
- }
159
- =end
160
- # Cleanup the database for earlier executions
161
-
162
- Og::Database.drop!(config)
163
-
164
- # Initialize Og
165
-
166
- db = Og::Database.new(config)
167
-
168
- # Create some articles
169
-
170
- a1 = Article.new("Title1", "Body1")
171
- a1.save!
172
-
173
- # shortcut
174
- a2 = Article.create("Title2", "Body2")
175
-
176
- puts "\n\n"
177
- puts "* Get and print all articles:"
178
- articles = Article.all()
179
- articles.each { |a| puts a }
180
-
181
- # Create some comments
182
-
183
- c1 = ArticleComment.new("Comment 1")
184
- c1.article = a1
185
- c1.save!
186
-
187
- c2 = ArticleComment.new("Comment 2")
188
- # alternative way to set the parent.
189
- c2.article_oid = a1.oid
190
- # an alternative way to save
191
- db << c2
192
-
193
- # an alternative (easier and cooler) way to add children in a
194
- # has_many relation:
195
- c3 = ArticleComment.new("Comment 3")
196
- # add_comment is automatically added by Og.
197
- a1.add_comment(c3)
198
-
199
- puts "\n\n"
200
- puts "* Print all all comments for article 1:"
201
- a1.comments.each { |c| puts c }
202
-
203
- # Most Og commands allow you to fine-tune the low level
204
- # SQL code by passing extra_sql parameters, here is an
205
- # example
206
- puts "\n\n"
207
- puts "* comments with sql finetunings:"
208
- # use a standard SQL limit clause
209
- a1.comments("LIMIT 2").each { |c| puts c }
210
-
211
-
212
- # Change a managed object
213
- a1.title = "Changed Title"
214
- # Og knows that this is a managed object and executes
215
- # an SQL UPDATE instead of an SQL INSERT
216
- a1.save!
217
-
218
- puts "\n\n"
219
- Article.all.each { |a| puts a }
220
-
221
- # The previous command updates the whole object. It is used
222
- # when there are many updates or you dont care about speed.
223
- # To update only specific fields use pupdate or properties_update
224
- a2.pupdate! "title='A specific title'"
225
-
226
- puts "\n\n"
227
- Article.all.each { |a| puts a }
228
-
229
- # delete an object
230
- ArticleComment.delete(c3)
231
-
232
- puts "\n\n"
233
- ArticleComment.all.each { |a| puts a }
234
-
235
-
236
- # Serialize a hash
237
- a1.options = { "k1" => "val1", "k2" => "val2" }
238
- a1.save!
239
-
240
- # lookup an object
241
- article = Article[a1.oid]
242
-
243
- puts "\n\n"
244
- puts article.options.inspect
245
-
246
- u = User.new("gmosx")
247
- u.save!
248
-
249
- article = Article[1]
250
- # you can also lookup by the name property.
251
- article.author = User["gmosx"]
252
- article.save!
253
-
254
- part = Part.new("admin")
255
- part.article = article
256
- part.save!
257
-
258
- article.parts.each { |pa| puts pa }
259
-
260
- puts "\n\n"
261
- puts '---'
262
-
263
- c1 = Category.new("Category1").save!
264
- c2 = Category.new("Category2").save!
265
-
266
- article.add_category(c1)
267
- article.add_category(c2)
268
-
269
- puts '---'
270
-
271
- article.categories.each { |c| puts c.title }
272
-
273
- puts '---'
274
-
275
- c2.articles.each { |a| puts a.title }
276
-
277
- article.delete_category(c1)
278
-
279
- puts '---'
280
-
281
- article.categories.each { |c| puts c.title }
282
-
283
- # create and save the article in one step.
284
- article = Article.create("title", "body")
285
-
286
- puts '--', article.oid
Binary file