spiderfw 0.6.23 → 0.6.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/CHANGELOG +10 -1
  2. data/README.rdoc +1 -1
  3. data/VERSION +1 -1
  4. data/apps/config_editor/_init.rb +1 -2
  5. data/apps/config_editor/controllers/config_editor_controller.rb +1 -7
  6. data/apps/core/admin/controllers/admin_controller.rb +1 -1
  7. data/apps/core/admin/public/css/sass/admin.css +35 -31
  8. data/apps/core/admin/public/sass/admin.scss +6 -1
  9. data/apps/core/components/widgets/crud/crud.shtml +2 -2
  10. data/apps/core/components/widgets/table/table.rb +5 -5
  11. data/apps/core/forms/tags/element_row.erb +15 -10
  12. data/apps/core/forms/widgets/form/form.rb +35 -22
  13. data/apps/core/forms/widgets/inputs/checkbox/checkbox.shtml +2 -2
  14. data/apps/core/forms/widgets/inputs/date_time/date_time.shtml +2 -2
  15. data/apps/core/forms/widgets/inputs/file_input/file_input.shtml +2 -2
  16. data/apps/core/forms/widgets/inputs/html_area/html_area.shtml +2 -2
  17. data/apps/core/forms/widgets/inputs/input/input.shtml +2 -2
  18. data/apps/core/forms/widgets/inputs/password/password.shtml +2 -2
  19. data/apps/core/forms/widgets/inputs/search_select/search_select.shtml +1 -1
  20. data/apps/core/forms/widgets/inputs/select/select.shtml +2 -2
  21. data/apps/core/forms/widgets/inputs/text/text.shtml +2 -2
  22. data/apps/core/forms/widgets/inputs/text_area/text_area.shtml +2 -2
  23. data/apps/core/forms/widgets/inputs/time_span/time_span.shtml +1 -1
  24. data/blueprints/home/config.ru +8 -0
  25. data/lib/spiderfw/app.rb +416 -224
  26. data/lib/spiderfw/cmd/commands/app.rb +243 -239
  27. data/lib/spiderfw/cmd/commands/cert.rb +421 -417
  28. data/lib/spiderfw/cmd/commands/config.rb +85 -82
  29. data/lib/spiderfw/cmd/commands/console.rb +64 -40
  30. data/lib/spiderfw/cmd/commands/content.rb +29 -25
  31. data/lib/spiderfw/cmd/commands/create.rb +58 -54
  32. data/lib/spiderfw/cmd/commands/model.rb +118 -114
  33. data/lib/spiderfw/cmd/commands/setup.rb +55 -51
  34. data/lib/spiderfw/cmd/commands/test.rb +63 -59
  35. data/lib/spiderfw/cmd/commands/webserver.rb +56 -51
  36. data/lib/spiderfw/config/options/spider.rb +4 -3
  37. data/lib/spiderfw/controller/controller.rb +2 -0
  38. data/lib/spiderfw/controller/http_controller.rb +1 -2
  39. data/lib/spiderfw/controller/mixins/static_content.rb +3 -3
  40. data/lib/spiderfw/controller/mixins/visual.rb +30 -15
  41. data/lib/spiderfw/controller/response.rb +84 -0
  42. data/lib/spiderfw/controller/session/file_session.rb +2 -2
  43. data/lib/spiderfw/http/adapters/rack.rb +12 -13
  44. data/lib/spiderfw/http/server.rb +80 -46
  45. data/lib/spiderfw/i18n/cldr.rb +6 -9
  46. data/lib/spiderfw/model/base_model.rb +103 -23
  47. data/lib/spiderfw/model/condition.rb +110 -25
  48. data/lib/spiderfw/model/mappers/db_mapper.rb +14 -6
  49. data/lib/spiderfw/model/mappers/mapper.rb +440 -197
  50. data/lib/spiderfw/model/model.rb +105 -21
  51. data/lib/spiderfw/model/model_hash.rb +9 -1
  52. data/lib/spiderfw/model/query.rb +50 -9
  53. data/lib/spiderfw/model/query_set.rb +211 -44
  54. data/lib/spiderfw/model/request.rb +28 -21
  55. data/lib/spiderfw/model/storage/base_storage.rb +125 -10
  56. data/lib/spiderfw/model/storage/db/db_storage.rb +7 -4
  57. data/lib/spiderfw/model/storage.rb +8 -1
  58. data/lib/spiderfw/setup/spider_setup_wizard.rb +9 -7
  59. data/lib/spiderfw/spider.rb +270 -43
  60. data/lib/spiderfw/templates/layout.rb +9 -4
  61. data/lib/spiderfw/templates/resources/sass.rb +3 -2
  62. data/lib/spiderfw/templates/template.rb +1 -0
  63. data/lib/spiderfw/utils/annotations.rb +3 -1
  64. data/lib/spiderfw/utils/logger.rb +1 -1
  65. data/lib/spiderfw/utils/monkey/symbol.rb +4 -2
  66. data/lib/spiderfw/utils/shared_store/file_shared_store.rb +2 -2
  67. data/lib/spiderfw/utils/thread_out.rb +3 -1
  68. data/public/css/error_page.css +83 -0
  69. data/public/js/error_page.js +5 -0
  70. data/spider.gemspec +4 -1
  71. data/templates/email/error.erb +9 -0
  72. metadata +28 -12
  73. data/apps/config_editor/widgets/edit_bool/edit_bool.rb +0 -8
  74. data/apps/config_editor/widgets/edit_bool/edit_bool.shtml +0 -5
@@ -4,6 +4,11 @@ require 'spiderfw/model/identity_mapper'
4
4
 
5
5
  module Spider
6
6
 
7
+ # Spider::Model is the namespace containing all data-related classes and modules.
8
+ #
9
+ # In addition, it implements some helper methods.
10
+ #
11
+ # See {BaseModel} for the base class that must be subclassed by app's models.
7
12
  module Model
8
13
 
9
14
  @base_types = [
@@ -11,17 +16,23 @@ module Spider
11
16
  Spider::DataTypes::Bool, Spider::DataTypes::PK
12
17
  ]
13
18
 
14
- # Base types are:
15
- #
19
+ # Returns a list of the base types, which must be handled by all mappers.
20
+ #
16
21
  # String, Spider::DataTypes::Text, Fixnum, Float, BigDecimal, Date, DateTime, Spider::DataTypes::Bool.
17
22
  #
18
23
  # These types must be handled by all mappers.
24
+ # @return [Array] An array of base types
19
25
  def self.base_types
20
26
  @base_types
21
27
  end
22
28
 
23
- # Returns the base type corresponding to class. Will walk superclasses and DataType info until
24
- # a base type is found.
29
+ # Returns the base type corresponding to a class.
30
+ #
31
+ # For BaseModels, the class itself will be returned; otherwise, will walk superclasses and DataType info
32
+ # until one of the {Model.base_types} is found.
33
+ #
34
+ # @param [Class] class
35
+ # @return [Class] The Base Type
25
36
  def self.base_type(klass)
26
37
  k = klass
27
38
  while (k && !base_types.include?(k))
@@ -30,8 +41,9 @@ module Spider
30
41
  return k
31
42
  end
32
43
 
33
- # TODO: remove?
34
- def self.ruby_type(klass) #:nodoc:
44
+ # @param [Class] A DataType subclass
45
+ # @return [Class] The Ruby class corresponding to a Spider DataType
46
+ def self.ruby_type(klass)
35
47
  map_types = {
36
48
  Spider::DataTypes::Text => String,
37
49
  Spider::DataTypes::Bool => FalseClass,
@@ -42,8 +54,11 @@ module Spider
42
54
  return klass
43
55
  end
44
56
 
57
+ # @private
45
58
  # An iteration in the search for base type.
46
- def self.simplify_type(klass) #:nodoc:
59
+ # @param [Class] class
60
+ # @return [Class] simplified type
61
+ def self.simplify_type(klass)
47
62
  map_types = {
48
63
 
49
64
  }
@@ -56,7 +71,12 @@ module Spider
56
71
  end
57
72
 
58
73
 
59
- # Returns the identity-mapped object
74
+ # Retrieves an object corresponding to gived values from the IdentityMapper, or puts it there if not found.
75
+ # @param [Class>BaseModel] The model
76
+ # @parm [Object] val A BaseModel instance, or a Hash of values, or a primary key for the model
77
+ # @param [bool] set_loaded If true, when instantiating an object from hash values, set the values as
78
+ # if they were loaded from the storage
79
+ # @return [BaseModel] The object retrieved from the IdentityMapper
60
80
  def self.get(model, val=nil, set_loaded=false)
61
81
  if (val && !val.is_a?(Hash))
62
82
  if (model.primary_keys.length == 1)
@@ -73,6 +93,10 @@ module Spider
73
93
  end
74
94
 
75
95
  # Puts an object into the IdentityMapper
96
+ # @param [BaseMode] object to place into the IdentityMapper
97
+ # @param [bool] check If true, if the object already exists in the IdentityMapper it will be merged.
98
+ # If false, if the object already exists it will be overwritten.
99
+ # @return [BaseModel] The object, as present in the IdentityMapper after the put
76
100
  def self.put(obj, check=false)
77
101
  if (identity_mapper)
78
102
  return identity_mapper.put(obj, check)
@@ -81,24 +105,35 @@ module Spider
81
105
  end
82
106
  end
83
107
 
84
- def self.identity_mapper #:nodoc:
108
+ # @return [IdentityMapper] The current IdentityMapper, if active
109
+ def self.identity_mapper
85
110
  Spider.current[:identity_mapper]
86
111
  end
87
112
 
88
- def self.identity_mapper=(im) #:nodoc:
113
+ # @param [IdentityMapper] im The IdentityMapper to activate for the current request
114
+ # @return [IdentityMapper]
115
+ def self.identity_mapper=(im)
89
116
  Spider.current[:identity_mapper] = im
90
117
  end
91
118
 
119
+ # Starts a new Unit Of Work
120
+ # @return [UnitOfWork]
92
121
  def self.start_unit_of_work
93
122
  uow = UnitOfWork.new
94
123
  uow.start
95
124
  end
96
125
 
126
+ # Stops the current Unit Of Work
127
+ # @return [void]
97
128
  def self.stop_unit_of_work
98
129
  Spider.current[:unit_of_work].stop
99
130
  end
100
131
 
101
- def self.unit_of_work(&proc) #:nodoc:
132
+ # @param [Proc] proc If supplied and no Unit Of Work is running, executes the block inside
133
+ # a new Unit Of Work
134
+ # @return [UnitOfWork] the current Unit Of Work, if no block was passed; otherwise, the Unit Of Work that
135
+ # was used to run the block
136
+ def self.unit_of_work(&proc)
102
137
  uow = Spider.current[:unit_of_work]
103
138
  if !uow
104
139
  if proc
@@ -108,17 +143,28 @@ module Spider
108
143
  return uow
109
144
  end
110
145
 
111
-
146
+ # Sets the UnitOfWork to use for the current request
147
+ # @param [UnitOfWork] uow
148
+ # @return [UnitOfWork]
112
149
  def self.unit_of_work=(uow)
113
150
  Spider.current[:unit_of_work] = uow
114
151
  end
115
152
 
153
+ # Executes a block inside a new Unit Of Work
154
+ #
155
+ # **Note**: you should almost always use {Model.in_unit} instead, since
156
+ # a Unit Of Work without an Identity Mapper can be problematic.
157
+ # @param [Proc] proc The block to execute
158
+ # @return [UnitOfWork] The Unit Of Work that was used to run the block
116
159
  def self.with_unit_of_work(&proc)
117
160
  with_identity_mapper do
118
161
  return unit_of_work(&proc)
119
162
  end
120
163
  end
121
164
 
165
+ # Executes a block without running in Unit Of Work
166
+ # @param [Proc] proc The block to run without a unit of work
167
+ # @return [UnitOfWork] The previously active Unit Of Work (if any)
122
168
  def self.no_unit_of_work(&proc)
123
169
  uow = self.unit_of_work
124
170
  self.unit_of_work = nil
@@ -126,10 +172,14 @@ module Spider
126
172
  self.unit_of_work = uow
127
173
  end
128
174
 
175
+ # @return [bool] True if there is an active Unit Of Work, false otherwise
129
176
  def self.unit_of_work_running?
130
177
  self.unit_of_work && self.unit_of_work.running?
131
178
  end
132
179
 
180
+ # Executes a block without Identity Mapper
181
+ # @param [Proc] proc The block to run without the Identity Mapper
182
+ # @return [IdentityMapper] The previously active Identity Mapper (if any)
133
183
  def self.no_identity_mapper(&proc)
134
184
  im = self.identity_mapper
135
185
  self.identity_mapper = nil
@@ -137,6 +187,9 @@ module Spider
137
187
  self.identity_mapper = im
138
188
  end
139
189
 
190
+ # Executes a block without Identity Mapper and Unit Of Work
191
+ # @param [Proc] proc The block to run
192
+ # @return [UnitOfWork] The previously active Unit Of Work (if any)
140
193
  def self.no_context(&proc)
141
194
  uow = self.unit_of_work
142
195
  self.unit_of_work = nil
@@ -148,7 +201,10 @@ module Spider
148
201
 
149
202
  end
150
203
 
151
- # Executes the block in the context of the main IdentityMapper.
204
+ # Executes a block in the context of the current IdentityMapper, if one is active.
205
+ # If no IdentityMapper is running, the code is executed inside a new Identity Mapper
206
+ # @param [Proc] proc The block to run
207
+ # @return [IdentityMapper] The used Identity Mapper
152
208
  def self.with_identity_mapper(&proc)
153
209
  if identity_mapper
154
210
  yield identity_mapper
@@ -159,6 +215,9 @@ module Spider
159
215
  end
160
216
  end
161
217
 
218
+ # Executes a block inside a Unit Of Work and Identity Mapper
219
+ # @param [Proc] proc The block to run
220
+ # @return [void]
162
221
  def self.in_unit(&proc)
163
222
  uow = self.unit_of_work
164
223
  self.start_unit_of_work unless uow
@@ -172,10 +231,16 @@ module Spider
172
231
 
173
232
  end
174
233
 
175
- # Syncs the schema with the storage.
176
- #--
177
- # FIXME: this is clearly db specific. Move somewhere else.
178
- def self.sync_schema(model_or_app, force=false, options={}) #:nodoc:
234
+ # Syncs the schema for a model, or for all models within an app, with the storage.
235
+ # @param [Class>BaseModel|Module>Spider::App] model_or_app
236
+ # @param [bool] force If true, allow operations that could cause data loss
237
+ # @param [Hash] options Options can be:
238
+ # * :no_sync Don't actually run the sync, only check the operations to run
239
+ # * :drop_tables Drop unneeded tables
240
+ # @return [void]
241
+ def self.sync_schema(model_or_app, force=false, options={})
242
+
243
+ # FIXME: this is clearly db specific. Move somewhere else.
179
244
  models = []
180
245
  mod = const_get_full(model_or_app)
181
246
  if (mod.is_a?(Module) && mod.include?(Spider::App))
@@ -215,7 +280,9 @@ module Spider
215
280
  end
216
281
  end
217
282
 
218
- # Load YAML data
283
+ # Load YAML data to the storage
284
+ # @param [String] file File to load data from
285
+ # @param [bool] truncate If true, delete all data from the models in the file before inserting new data
219
286
  def self.load_fixtures(file, truncate=false)
220
287
  if (file =~ /\.([^\.]+)$/)
221
288
  extension = $1
@@ -257,19 +324,23 @@ module Spider
257
324
  end
258
325
 
259
326
  # Generic Model error.
260
-
261
327
  class ModelException < RuntimeError
262
328
  end
263
329
 
264
330
  # Error raised when data can't be accepted.
265
-
266
331
  class FormatError < ::FormatError
267
- attr_reader :element, :value
332
+ # @return [Element]
333
+ attr_reader :element
334
+ # @return [Object]
335
+ attr_reader :value
268
336
 
269
337
  # Takes an Element, the value, and a message.
270
338
  # The message should be a format specification; it will be %'d with the value.
271
339
  # error = FormatError.new(my_element, 3, "Element value %s is wrong.")
272
340
  # error.to_s => "Element value 3 is wrong."
341
+ # @param [Element] value
342
+ # @param [Object] value
343
+ # @param [String] message The error message
273
344
  def initialize(element, value, message)
274
345
  @element = element
275
346
  @message = message
@@ -287,9 +358,20 @@ module Spider
287
358
 
288
359
  end
289
360
 
361
+ # Error raised when data is of the wrong type
290
362
  class TypeError < ArgumentError
291
363
  end
292
364
 
365
+ # Sorts an Array of models, placing subclasses before superclasses.
366
+ #
367
+ # If :association_dependencies is true, models having an association to another model will be placed after the associated
368
+ # model.
369
+ #
370
+ # This can be used to insert a dump of data, ensuring later models only depend on already inserted objects.
371
+ # @param [Array] models An array of BaseModel subclasses
372
+ # @param [Hash] options Options can be:
373
+ # * :association_dependencies If true, sort associated models before the model associating them
374
+ # @return [Array] The sorted array
293
375
  def self.sort(models, options={})
294
376
  options = {
295
377
  :association_dependencies => true
@@ -300,6 +382,7 @@ module Spider
300
382
 
301
383
  require 'tsort'
302
384
 
385
+ # Helper class from sorting models using TSort
303
386
  class Sorter
304
387
  include TSort
305
388
 
@@ -351,6 +434,7 @@ module Spider
351
434
 
352
435
  end
353
436
 
437
+ # Helper class for sorting models
354
438
  class SortTask
355
439
  attr_reader :model, :dependencies
356
440
 
@@ -11,18 +11,24 @@ module Spider; module Model
11
11
  # mh['test.name'] = 'Devilish Kitty'
12
12
  # => {:test => {:name => 'Devilish Kitty', :color => 'black'}}
13
13
  class ModelHash < Hash
14
- alias :modelhash_orig_set :[]= # :nodoc:
14
+ # Original hash value assignment
15
+ alias :modelhash_orig_set :[]=
15
16
 
17
+ # @param [Hash] hash A Hash to get data from
16
18
  def initialize(hash=nil)
17
19
  super()
18
20
  merge!(hash) if (hash && hash.is_a?(Hash))
19
21
  end
20
22
 
21
23
  # Returns a new instance when needed by an assignement. May be overridden by subclasses.
24
+ # @return [ModelHash]
22
25
  def get_deep_obj
23
26
  return self.class.new
24
27
  end
25
28
 
29
+ # Value assignment
30
+ # @param [String|Symbol|Element] key
31
+ # @param [Object] value
26
32
  def []=(key, val)
27
33
  if (val.is_a?(BaseModel))
28
34
  n = self.class.new
@@ -43,6 +49,8 @@ module Spider; module Model
43
49
  end
44
50
  end
45
51
 
52
+ # Value retrieval
53
+ # @param [String|Symbol|Element] key
46
54
  def [](key)
47
55
  # TODO: deep
48
56
  key = key.name if key.is_a?(Element)
@@ -8,27 +8,41 @@ module Spider; module Model
8
8
 
9
9
  class Query
10
10
  # An array of element-direction (:asc or :desc) pairs
11
+ # @return [Array]
11
12
  attr_accessor :order
12
13
  # Skip the first :offset objects
14
+ # @return [Fixnum]
13
15
  attr_accessor :offset
14
16
  # Limit the returned results to :limit objects
17
+ # @return [Fixnum]
15
18
  attr_accessor :limit
16
19
  # Requests subclasses of the queried model
20
+ # @return [Array]
17
21
  attr_accessor :polymorphs
18
22
  # The Condition instance
23
+ # @return [Condition]
19
24
  attr_reader :condition
20
25
  # The Request instance
26
+ # @return [Request]
21
27
  attr_reader :request
28
+ # @return [Fixnum] number of rows per page, when using pagination
22
29
  attr_reader :page_rows
30
+ # @return [Fixnum] current page, when using pagination
23
31
  attr_reader :page
32
+ # @return [Array] Elements the mapper has to group_by
24
33
  attr_accessor :group_by_elements
25
34
 
26
35
  # Instantiates a new query, calling Condition#where on the condition.
36
+ # See {Query#new} for arguments
37
+ # Return #{Condition}
27
38
  def self.where(*params)
28
39
  return self.class.new.condition.where(*params)
29
40
  end
30
41
 
31
42
  # Parameters are a Condition and a Request. If a block is given, it will be parsed by the Condition.
43
+ # @param [Condition] condition
44
+ # @param [Request] request
45
+ # @param [Proc] proc Optional block used to construct the Condition
32
46
  def initialize(condition = nil, request=nil, &proc)
33
47
  @condition = condition.is_a?(Condition) ? condition : Condition.new(condition)
34
48
  @request = request.is_a?(Request) ? request : Request.new(request)
@@ -39,7 +53,10 @@ module Spider; module Model
39
53
  end
40
54
  end
41
55
 
42
- # Sets the condition. If val is not a Condition, will attempt to convert it to one.
56
+ # Sets the condition. If val is not a Condition, will attempt to convert it to one
57
+ # (val will be passed to {Condition.new}).
58
+ # @param [Condition|Object]
59
+ # @return [void]
43
60
  def condition=(val)
44
61
  if (!val.is_a?(Condition))
45
62
  @condition = Condition.new(val)
@@ -48,7 +65,10 @@ module Spider; module Model
48
65
  end
49
66
  end
50
67
 
51
- # Sets the request. If val is not a Request, will attempt to convert it to one.
68
+ # Sets the request. If val is not a Request, will attempt to convert it to one
69
+ # (val will be passed to {Request.new}).
70
+ # @param [Request|Object]
71
+ # @return [void]
52
72
  def request=(val)
53
73
  if (!val.is_a?(Request))
54
74
  @request = Request.new(val)
@@ -65,6 +85,8 @@ module Spider; module Model
65
85
  # Example:
66
86
  # query.order_by(:element, :desc)
67
87
  # query.order_by('name desc', :rating)
88
+ # @param [*Symbol|String] elements A list of elements
89
+ # @return [self]
68
90
  def order_by(*elements)
69
91
  if (elements.length == 2 && [:asc, :desc].include?(elements[1]))
70
92
  @order << elements
@@ -84,6 +106,9 @@ module Spider; module Model
84
106
  return self
85
107
  end
86
108
 
109
+ # Elements to group_by (used by some mappers for aggregate queries)
110
+ # @param [*Symbol|String] elements A list of elements
111
+ # @return [self]
87
112
  def group_by(*elements)
88
113
  @group_by_elements ||= []
89
114
  @group_by_elements += elements
@@ -91,6 +116,8 @@ module Spider; module Model
91
116
  end
92
117
 
93
118
  # Adds each element in the given list to the request.
119
+ # @param [*Symbol|String] elements A list of elements
120
+ # @return [self]
94
121
  def select(*elements)
95
122
  elements.each do |element|
96
123
  @request.request(element.to_s)
@@ -100,13 +127,19 @@ module Spider; module Model
100
127
 
101
128
  # Takes an argument or a block.
102
129
  # If given an argument, will use it as a Condition. If given a block, will use it on the Condition.
130
+ # @param [Condition] condition
131
+ # @param [Proc] proc Block used to construct the Condition
103
132
  def where(condition=nil, &proc)
104
133
  condition = Condition.new(&proc) unless (condition)
105
134
  @condition << condition
106
135
  return self
107
136
  end
108
137
 
109
- # Requests a polymorph.
138
+ # Requests a polymorph. This means that the mapper will try to differentiate the result into
139
+ # the subclasses given here.
140
+ # @param [Class<BaseModel] type The polymorph class to look for
141
+ # @param [Request] request Additional elements of the subclass to request
142
+ # @return [self]
110
143
  def with_polymorph(type, request=nil)
111
144
  query = self.class.new(query) unless query.is_a?(self.class)
112
145
  @polymorphs << type
@@ -119,28 +152,34 @@ module Spider; module Model
119
152
  end
120
153
 
121
154
  # Requests only polymorphs. (see Request#only_polymorphs).
155
+ # @return [Request]
122
156
  def only_polymorphs
123
157
  @request.only_polymorphs
124
158
  end
125
159
 
160
+ # Load also objects that belong to the superclass, and don't have this subclass.
161
+ # See #Request#with_superclass.
162
+ # @return [Request]
126
163
  def with_superclass
127
164
  @request.with_superclass
128
165
  end
129
166
 
130
- def first
131
- self.limit = 1
132
- end
133
-
167
+ # Request only the first result.
168
+ # @return [void]
134
169
  def only_one
135
170
  self.limit = 1
136
171
  @only_one = true
137
172
  end
138
173
 
139
-
174
+ # @return [bool] Was only the first record requested?
140
175
  def only_one?
141
176
  @only_one
142
177
  end
143
178
 
179
+ # Pagination: request the given page, for given rows per page
180
+ # @param [Fixnum] page
181
+ # @param [Fixnum] rows
182
+ # @return [self]
144
183
  def page(page, rows)
145
184
  page = page.to_i
146
185
  page = 1 if page == 0
@@ -156,11 +195,13 @@ module Spider; module Model
156
195
  # information methods #
157
196
  ##############################
158
197
 
159
- def polymorphs? # :nodoc:
198
+ # @return [bool] Are there requested polymorphs?
199
+ def polymorphs?
160
200
  @polymorphs.length > 0
161
201
  end
162
202
 
163
203
  # Returns a deep copy.
204
+ # @return [Query]
164
205
  def clone
165
206
  cl = self.class.new(@condition.clone, @request.clone)
166
207
  cl.order = @order.clone