inat-get 0.8.0.11 → 0.8.0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -0
  3. data/bin/inat-get +1 -1
  4. data/inat-get.gemspec +6 -6
  5. data/lib/extra/enum.rb +4 -0
  6. data/lib/extra/period.rb +15 -0
  7. data/lib/inat/app/application.rb +4 -3
  8. data/lib/inat/app/config/messagelevel.rb +3 -1
  9. data/lib/inat/app/config/shiftage.rb +1 -1
  10. data/lib/inat/app/config/updatemode.rb +1 -1
  11. data/lib/inat/app/config.rb +6 -2
  12. data/lib/inat/app/globals.rb +6 -3
  13. data/lib/inat/app/info.rb +18 -13
  14. data/lib/inat/app/logging.rb +3 -3
  15. data/lib/inat/app/preamble.rb +1 -1
  16. data/lib/inat/app/status.rb +3 -9
  17. data/lib/inat/app/task/context.rb +9 -3
  18. data/lib/inat/app/task/dsl.rb +5 -3
  19. data/lib/inat/app/task.rb +2 -2
  20. data/lib/inat/data/api.rb +210 -181
  21. data/lib/inat/data/db.rb +9 -4
  22. data/lib/inat/data/ddl.rb +24 -5
  23. data/lib/inat/data/entity/comment.rb +8 -4
  24. data/lib/inat/data/entity/flag.rb +7 -3
  25. data/lib/inat/data/entity/identification.rb +9 -4
  26. data/lib/inat/data/entity/observation.rb +27 -14
  27. data/lib/inat/data/entity/observationphoto.rb +7 -3
  28. data/lib/inat/data/entity/observationsound.rb +6 -7
  29. data/lib/inat/data/entity/photo.rb +9 -3
  30. data/lib/inat/data/entity/place.rb +11 -2
  31. data/lib/inat/data/entity/project.rb +16 -10
  32. data/lib/inat/data/entity/projectadmin.rb +4 -4
  33. data/lib/inat/data/entity/projectobservationrule.rb +3 -4
  34. data/lib/inat/data/entity/request.rb +7 -3
  35. data/lib/inat/data/entity/sound.rb +7 -2
  36. data/lib/inat/data/entity/taxon.rb +11 -3
  37. data/lib/inat/data/entity/user.rb +7 -3
  38. data/lib/inat/data/entity/vote.rb +7 -3
  39. data/lib/inat/data/entity.rb +38 -24
  40. data/lib/inat/data/enums/conservationstatus.rb +3 -3
  41. data/lib/inat/data/enums/geoprivacy.rb +3 -1
  42. data/lib/inat/data/enums/iconictaxa.rb +1 -1
  43. data/lib/inat/data/enums/identificationcategory.rb +1 -1
  44. data/lib/inat/data/enums/licensecode.rb +5 -2
  45. data/lib/inat/data/enums/projectadminrole.rb +1 -1
  46. data/lib/inat/data/enums/projecttype.rb +5 -3
  47. data/lib/inat/data/enums/qualitygrade.rb +1 -1
  48. data/lib/inat/data/enums/rank.rb +1 -1
  49. data/lib/inat/data/model.rb +73 -24
  50. data/lib/inat/data/query.rb +14 -9
  51. data/lib/inat/data/sets/dataset.rb +10 -6
  52. data/lib/inat/data/sets/list.rb +8 -3
  53. data/lib/inat/data/sets/listers.rb +10 -4
  54. data/lib/inat/data/sets/wrappers.rb +111 -82
  55. data/lib/inat/data/types/location.rb +17 -8
  56. data/lib/inat/data/types/std.rb +171 -176
  57. data/lib/inat/report/report_dsl.rb +205 -0
  58. data/lib/inat/report/table.rb +11 -3
  59. data/lib/inat/utils/deep.rb +25 -19
  60. metadata +6 -5
  61. data/lib/inat/data/cache.rb +0 -9
@@ -3,12 +3,17 @@
3
3
  require_relative '../app/globals'
4
4
  require_relative 'types/std'
5
5
 
6
- autoload :Entity, 'inat/data/entity'
6
+ module INat::Data
7
+ autoload :Entity, 'inat/data/entity'
8
+ end
9
+
10
+ module INat::Data; end
7
11
 
8
- class Model
12
+ class INat::Data::Model
9
13
 
10
- include LogDSL
14
+ include INat::App::Logger::DSL
11
15
 
16
+ # @private
12
17
  class Field
13
18
 
14
19
  attr_reader :model, :name, :type, :id_field
@@ -42,7 +47,10 @@ class Model
42
47
 
43
48
  end
44
49
 
45
- class ScalarField < Model::Field
50
+ # @private
51
+ class ScalarField < Field
52
+
53
+ using INat::Types::Std
46
54
 
47
55
  attr_reader :index, :unique, :primary_key
48
56
 
@@ -51,7 +59,7 @@ class Model
51
59
  end
52
60
 
53
61
  def initialize model, name, type, id_field, required, index, unique, primary_key
54
- if Class === type && Entity > type && id_field == nil
62
+ if Class === type && INat::Data::Entity > type && id_field == nil
55
63
  id_field = "#{ name }_id".intern
56
64
  end
57
65
  super model, name, type, id_field
@@ -74,7 +82,7 @@ class Model
74
82
  md.define_method "#{ ni }=" do |value|
75
83
  prevalue = instance_variable_get "@#{ ni }"
76
84
  if prevalue != value
77
- debug "ASS: #{ self.id }: #{ ni } = #{ prevalue.inspect } <=> #{ value.inspect }" if prevalue != nil && self.class.name == 'Taxon'
85
+ debug "ASS: #{ self.id }: #{ ni } = #{ prevalue.inspect } <=> #{ value.inspect }" if prevalue != nil && self.class.short_name == 'Taxon'
78
86
  instance_variable_set "@#{ ni }", value
79
87
  instance_variable_set "@saved", false
80
88
  end
@@ -92,7 +100,7 @@ class Model
92
100
  md.define_method "#{ nm }=" do |value|
93
101
  prevalue = instance_variable_get "@#{ ni }"
94
102
  if prevalue != value&.id
95
- debug "ASS: #{ self.id }: #{ nm } / #{ ni } = #{ prevalue.inspect } <=> #{ value.inspect }" if prevalue != nil && self.class.name == 'Taxon'
103
+ debug "ASS: #{ self.id }: #{ nm } / #{ ni } = #{ prevalue.inspect } <=> #{ value.inspect }" if prevalue != nil && self.class.short_name == 'Taxon'
96
104
  instance_variable_set "@#{ ni }", value&.id
97
105
  instance_variable_set "@saved", false
98
106
  end
@@ -105,7 +113,7 @@ class Model
105
113
  raise TypeError, "Invalid '#{ nm }' value: #{ value.inspect }!", caller unless tp === value || (value == nil && !rq)
106
114
  prevalue = instance_variable_get "@#{ nm }"
107
115
  if prevalue != value
108
- debug "ASS: #{ self.id }: #{ nm } = #{ prevalue.inspect } <=> #{ value.inspect }" if prevalue != nil && self.class.name == 'Taxon'
116
+ debug "ASS: #{ self.id }: #{ nm } = #{ prevalue.inspect } <=> #{ value.inspect }" if prevalue != nil && self.class.short_name == 'Taxon'
109
117
  instance_variable_set "@#{ nm }", value
110
118
  instance_variable_set "@saved", false
111
119
  end
@@ -207,7 +215,10 @@ class Model
207
215
 
208
216
  end
209
217
 
210
- class ArrayField < Model::Field
218
+ # @private
219
+ class ArrayField < Field
220
+
221
+ using INat::Types::Std
211
222
 
212
223
  attr_reader :back_field
213
224
 
@@ -223,7 +234,7 @@ class Model
223
234
  raise ArgumentError, "Argument 'id_field' is required for name '#{ name }'!", caller[1..]
224
235
  end
225
236
  end
226
- back_field = "#{ model.name.downcase }_id".intern if back_field == nil
237
+ back_field = "#{ model.short_name.downcase }_id".intern if back_field == nil
227
238
  super model, name, type, id_field
228
239
  @owned = owned
229
240
  @back_field = back_field
@@ -248,7 +259,7 @@ class Model
248
259
  value = value&.sort.uniq
249
260
  end
250
261
  if prevalue != value
251
- debug "ASS: #{ self.id }: #{ ni } = #{ prevalue.inspect } <=> #{ value.inspect } :: #{ caller[..2] }" if prevalue != nil && self.class.name == 'Taxon'
262
+ debug "ASS: #{ self.id }: #{ ni } = #{ prevalue.inspect } <=> #{ value.inspect } :: #{ caller[..2] }" if prevalue != nil && self.class.short_name == 'Taxon'
252
263
  instance_variable_set "@#{ ni }", value
253
264
  instance_variable_set "@saved", false
254
265
  end
@@ -274,7 +285,7 @@ class Model
274
285
  end
275
286
  prevalue = instance_variable_get("@#{ nm }")
276
287
  if prevalue&.sort != value&.sort
277
- debug "ASS: #{ self.id }: #{ nm } = #{ prevalue.inspect } <=> #{ value.inspect } :: #{ caller[..2] }" if prevalue != nil && self.class.name == 'Taxon'
288
+ debug "ASS: #{ self.id }: #{ nm } = #{ prevalue.inspect } <=> #{ value.inspect } :: #{ caller[..2] }" if prevalue != nil && self.class.short_name == 'Taxon'
278
289
  instance_variable_set "@#{ nm }", value
279
290
  instance_variable_set "@saved", false
280
291
  end
@@ -292,13 +303,16 @@ class Model
292
303
 
293
304
  end
294
305
 
295
- class ManyToManyField < Model::ArrayField
306
+ # @private
307
+ class ManyToManyField < ArrayField
308
+
309
+ using INat::Types::Std
296
310
 
297
311
  attr_reader :table_name, :link_field, :index
298
312
 
299
313
  def initialize model, name, type, id_field, owned, table_name, back_field, link_field, index
300
- table_name = "#{ model.name.downcase }_#{ name }".intern if table_name == nil
301
- link_field = "#{ type.name.downcase }_id".intern if link_field == nil
314
+ table_name = "#{ model.short_name.downcase }_#{ name }".intern if table_name == nil
315
+ link_field = "#{ type.short_name.downcase }_id".intern if link_field == nil
302
316
  super model, name, type, id_field, owned, back_field
303
317
  @table_name = table_name
304
318
  @link_field = link_field
@@ -327,7 +341,8 @@ class Model
327
341
 
328
342
  end
329
343
 
330
- class OneToManyField < Model::ArrayField
344
+ # @private
345
+ class OneToManyField < ArrayField
331
346
 
332
347
  def kind
333
348
  :backs
@@ -335,7 +350,8 @@ class Model
335
350
 
336
351
  end
337
352
 
338
- class SpecialField < Model::Field
353
+ # @private
354
+ class SpecialField < Field
339
355
 
340
356
  def initialize model, name, type, &block
341
357
  raise ArgumentError, "Block is required!", caller[1..] unless block_given?
@@ -359,7 +375,8 @@ class Model
359
375
 
360
376
  end
361
377
 
362
- class IgnoreField < Model::SpecialField
378
+ # @private
379
+ class IgnoreField < SpecialField
363
380
 
364
381
  def initialize model, name
365
382
  super model, name, Object do
@@ -433,7 +450,15 @@ class Model
433
450
  result.freeze
434
451
  end
435
452
 
436
- private def field name, type: nil, id_field: nil, required: false, index: false, unique: false, primary_key: false
453
+ # Defines a new field
454
+ # @param [Symbol] name
455
+ # @param [Class] type
456
+ # @return [void]
457
+ # @!macro [attach] field
458
+ # @api public
459
+ # @!attribute [rw]
460
+ # @return [$2] the +$1+ field
461
+ def field name, type: nil, id_field: nil, required: false, index: false, unique: false, primary_key: false
437
462
  raise TypeError, "Field name must be a Symbol!", caller unless Symbol === name
438
463
  raise TypeError, "Field type must be a Module!", caller unless Module === type
439
464
  raise TypeError, "Argument 'id_field' must be a Symbol!", caller unless Symbol === id_field || id_field == nil
@@ -446,9 +471,17 @@ class Model
446
471
  @fields[name].implement
447
472
  end
448
473
 
449
- private def links name, item_type: nil, ids_field: nil, owned: true, table_name: nil, back_field: nil, link_field: nil, index: false
474
+ # Defines a new many-to-many field
475
+ # @param [Symbol] name
476
+ # @param [Class] item_type
477
+ # @return [void]
478
+ # @!macro [attach] links
479
+ # @api public
480
+ # @!attribute [rw]
481
+ # @return [Array<$2>] the +$1+ field
482
+ def links name, item_type: nil, ids_field: nil, owned: true, table_name: nil, back_field: nil, link_field: nil, index: false
450
483
  raise TypeError, "Field name must be a Symbol!", caller unless Symbol === name
451
- raise TypeError, "Item type must be an Entity subclass!", caller unless Class === item_type && Entity > item_type
484
+ raise TypeError, "Item type must be an Entity subclass!", caller unless Class === item_type && INat::Entity > item_type
452
485
  raise TypeError, "Argument 'ids_field' must be a Symbol!", caller unless Symbol === ids_field || ids_field == nil
453
486
  raise TypeError, "Argument 'table_name' must be a Symbol!", caller unless Symbol === table_name || table_name == nil
454
487
  raise TypeError, "Argument 'back_field' must be a Symbol!", caller unless Symbol === back_field || back_field == nil
@@ -460,9 +493,17 @@ class Model
460
493
  @fields[name].implement
461
494
  end
462
495
 
463
- private def backs name, item_type: nil, ids_field: nil, owned: true, back_field: nil
496
+ # Defines a new one-to-many field
497
+ # @param [Symbol] name
498
+ # @param [Class] item_type
499
+ # @return [void]
500
+ # @!macro [attach] backs
501
+ # @api public
502
+ # @!attribute [rw]
503
+ # @return [Array<$2>] the +$1+ field
504
+ def backs name, item_type: nil, ids_field: nil, owned: true, back_field: nil
464
505
  raise TypeError, "Field name must be a Symbol!", caller unless Symbol === name
465
- raise TypeError, "Item type must be an Entity subclass!", caller unless Class === item_type && Entity > item_type
506
+ raise TypeError, "Item type must be an Entity subclass!", caller unless Class === item_type && INat::Entity > item_type
466
507
  raise TypeError, "Argument 'ids_field' must be a Symbol!", caller unless Symbol === ids_field || ids_field == nil
467
508
  raise TypeError, "Argument 'back_field' must be a Symbol!", caller unless Symbol === back_field || back_field == nil
468
509
  raise TypeError, "Argument 'owned' must be a Boolean!", caller unless Boolean === owned
@@ -471,7 +512,15 @@ class Model
471
512
  @fields[name].implement
472
513
  end
473
514
 
474
- private def block name, type: nil, &block
515
+ # Defines a new write-only field
516
+ # @param [Symbol] name
517
+ # @param [Class] type
518
+ # @return [void]
519
+ # @!macro [attach] block
520
+ # @api public
521
+ # @!attribute [w]
522
+ # @return [$2] the +$1+ field
523
+ def block name, type: nil, &block
475
524
  raise TypeError, "Field name must be a Symbol!", caller unless Symbol === name
476
525
  raise TypeError, "Field type must be a Module!", caller unless Module === type
477
526
  raise ArgumentError, "Block is required!", caller unless block_given?
@@ -14,9 +14,14 @@ require_relative 'types/std'
14
14
  require_relative 'types/location'
15
15
  require_relative 'types/extras'
16
16
 
17
- class Query
17
+ class INat::Query
18
18
 
19
- include LogDSL
19
+ using INat::Types::Std
20
+
21
+ include INat
22
+ include INat::App
23
+ include INat::App::Logger::DSL
24
+ include INat::Data::Types
20
25
 
21
26
  private def parse_accuracy value
22
27
  case value
@@ -1077,17 +1082,17 @@ class Query
1077
1082
  if mode != UpdateMode::MINIMAL
1078
1083
  actual_time = Time::new - Period::parse(G.config[:data][:update_period])
1079
1084
  end
1080
- actuals = Request::from_db_rows(DB.execute("SELECT * FROM requests WHERE time >= ?", actual_time.to_db)).select { |rq| self.in?(rq.query) }
1085
+ actuals = Entity::Request::from_db_rows(DB.execute("SELECT * FROM requests WHERE time >= ?", actual_time.to_db)).select { |rq| self.in?(rq.query) }
1081
1086
  end
1082
1087
  if actuals.empty? || mode == UpdateMode::FORCE
1083
1088
  # 2. Ищем чего бы обновить
1084
- request = Request::from_db_rows(DB.execute("SELECT * FROM requests WHERE query = ?", api_query)).first
1089
+ request = Entity::Request::from_db_rows(DB.execute("SELECT * FROM requests WHERE query = ?", api_query)).first
1085
1090
  updated_since = nil
1086
1091
  if request == nil
1087
1092
  query_string = api_query
1088
1093
  project_id = @api_params[:project_id]
1089
1094
  project_id = nil unless Integer === project_id
1090
- request = Request::create query_string, project_id
1095
+ request = Entity::Request::create query_string, project_id
1091
1096
  request.save
1092
1097
  else
1093
1098
  updated_since = request.time if mode != UpdateMode::RELOAD
@@ -1104,7 +1109,7 @@ class Query
1104
1109
  tt = nil
1105
1110
  cc = 0
1106
1111
  current_time = Time::new
1107
- API::query(:observations, **params) do |json, total|
1112
+ INat::API::query(:observations, **params) do |json, total|
1108
1113
  tt ||= total
1109
1114
  cc += 1
1110
1115
  pc = cc * 100 / tt
@@ -1113,7 +1118,7 @@ class Query
1113
1118
  pe = Period::make seconds: te
1114
1119
  pt = Period::make seconds: (Time::new - current_time).to_i
1115
1120
  Status::status nil, "Query \##{ @int_key } : R\##{ request.id } : parsed #{ format("%d of %d : %3d%% : time %s remain %s", cc, tt, pc, pt.to_hs, pe.to_hs) }"
1116
- obs = Observation::parse json
1121
+ obs = Entity::Observation::parse json
1117
1122
  obs.save
1118
1123
  DB.execute "INSERT OR REPLACE INTO request_observations (request_id, observation_id) VALUES (?, ?);", request.id, obs.id
1119
1124
  end
@@ -1123,12 +1128,12 @@ class Query
1123
1128
  # TODO: разобраться с удалением устаревшего
1124
1129
  # NEED: разобраться с частичной загрузкой — большие проекты грузятся недопустимо долго
1125
1130
  # возможно, стоит запараллелить обработку
1126
- request = Request::read(request.id).first
1131
+ request = Entity::Request::read(request.id).first
1127
1132
  end
1128
1133
  end
1129
1134
  # TODO: разобраться, где тупня
1130
1135
  sql, sql_args = db_where
1131
- result = Observation::from_db_rows(DB.execute("SELECT * FROM observations o#{ sql.empty? && '' || ' WHERE ' }#{ sql };", *sql_args))
1136
+ result = Entity::Observation::from_db_rows(DB.execute("SELECT * FROM observations o#{ sql.empty? && '' || ' WHERE ' }#{ sql };", *sql_args))
1132
1137
  if !@r_match.empty?
1133
1138
  result = result.filter { |o| self.match?(o) }
1134
1139
  end
@@ -3,10 +3,13 @@
3
3
  require_relative 'listers'
4
4
  require_relative 'list'
5
5
 
6
- class DataSet
6
+ class INat::Report::DataSet
7
+
8
+ include INat
9
+ include INat::Report
7
10
 
8
11
  attr_reader :time
9
- attr_reader :object
12
+ attr_accessor :object # TODO: переделать select так, чтобы не было необходимости во внешнем присваивании
10
13
  attr_reader :observations
11
14
 
12
15
  def initialize object, observations, time: Time::new
@@ -74,7 +77,8 @@ class DataSet
74
77
  alias :=== :include?
75
78
 
76
79
  def << observation
77
- raise TypeError, "Argument must be an Observation (#{ observation.inspect })!" unless Observation === observation
80
+ raise TypeError, "Argument must be an Observation (#{ observation.inspect })!" unless Entity::Observation === observation
81
+ # TODO: добавить массивы и прочее
78
82
  if !self.include?(observation)
79
83
  @observations << observation
80
84
  @by_id[observation.id] = observation
@@ -84,17 +88,17 @@ class DataSet
84
88
 
85
89
  def | other
86
90
  obj = @object == other.object ? @object : nil
87
- DataSet::new obj, @observations + other.observations, time: Time::new
91
+ INat::Report::DataSet::new obj, @observations + other.observations, time: Time::new
88
92
  end
89
93
 
90
94
  def & other
91
95
  obj = @object == other.object ? @object : nil
92
- DataSet::new obj, @observations.select { |o| other.include?(o) }, time: Time::new
96
+ INat::Report::DataSet::new obj, @observations.select { |o| other.include?(o) }, time: Time::new
93
97
  end
94
98
 
95
99
  def - other
96
100
  obj = @object == other.object ? @object : nil
97
- DataSet::new obj, @observations.select { |o| !other.include?(o) }, time: Time::new
101
+ INat::Report::DataSet::new obj, @observations.select { |o| !other.include?(o) }, time: Time::new
98
102
  end
99
103
 
100
104
  def to_a
@@ -1,8 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- autoload :DataSet, 'inat/data/sets/dataset'
3
+ module INat::Report
4
+ autoload :DataSet, 'inat/data/sets/dataset'
5
+ end
6
+
7
+ class INat::Report::List
4
8
 
5
- class List
9
+ include INat
10
+ include INat::Report
6
11
 
7
12
  attr_reader :lister, :sorter
8
13
 
@@ -77,7 +82,7 @@ class List
77
82
 
78
83
  def << some
79
84
  case some
80
- when Observation
85
+ when Entity::Observation
81
86
  key = @lister.call some
82
87
  if key != nil
83
88
  @data[key] ||= DataSet::new key, [], time: @time
@@ -2,14 +2,20 @@
2
2
 
3
3
  require_relative 'wrappers'
4
4
 
5
- module Listers
5
+ # TODO: возможно, загнать внутрь List?
6
+
7
+ module INat::Report::Listers
8
+
9
+ include INat::Report
10
+ include INat::Data::Types
6
11
 
7
12
  SPECIES = lambda { |o| o.normalized_taxon(Rank::COMPLEX .. Rank::HYBRID) }
8
13
  GENUS = lambda { |o| o.normalized_taxon(Rank::GENUS) }
9
14
  FAMILY = lambda { |o| o.normalized_taxon(Rank::FAMILY) }
10
- YEAR = lambda { |o| Year[o.observed_on] }
11
- MONTH = lambda { |o| Month[o.observed_on] }
12
- DAY = lambda { |o| Day[o.observed_on] }
15
+ YEAR = lambda { |o| Period::Year[o.observed_on] }
16
+ MONTH = lambda { |o| Period::Month[o.observed_on] }
17
+ DAY = lambda { |o| Period::Day[o.observed_on] }
18
+ WINTER = lambda { |o| Period::Winter[o.observed_on] }
13
19
  USER = lambda { |o| o.user }
14
20
 
15
21
  end
@@ -2,136 +2,165 @@
2
2
 
3
3
  require 'date'
4
4
 
5
- class Year
5
+ module INat::Report; end
6
+
7
+ # TODO: переделать в модуль namespace и Base-класс отдельно
8
+
9
+ class INat::Report::Period
6
10
 
7
11
  class << self
8
12
 
9
13
  private :new
10
14
 
11
- def [] source
12
- return nil if source == nil
13
- return source if Year === source
14
- year = case source
15
- when Date, Time
16
- source.year
15
+ def [] src
16
+ return nil if src == nil
17
+ return src if self === src
18
+ value = case src
19
+ when Date
20
+ self.date_to_value src
21
+ when Time
22
+ self.date_to_value src.to_date
17
23
  when String
18
- date = Date::parse source
19
- date.year
24
+ date = Date::parse src
25
+ self.date_to_value date
20
26
  when Integer
21
- source
27
+ src
22
28
  else
23
- raise TypeError, "Invalid year key: #{ source.inspect }!", caller
29
+ raise TypeError, "Invalid date: #{ src.inspect }", caller
24
30
  end
25
- @years ||= {}
26
- @years[year] ||= new year
27
- @years[year]
31
+ return nil if value == nil
32
+ @values ||= {}
33
+ @values[value] ||= new value
34
+ @values[value]
28
35
  end
29
36
 
30
37
  end
31
38
 
32
- attr_reader :year
39
+ attr_reader :value
33
40
 
34
- def initialize year
35
- @year = year
41
+ def initialize value
42
+ @value = value
36
43
  end
37
44
 
38
45
  include Comparable
39
46
 
40
47
  def <=> other
41
- return nil unless Year === other
42
- @year <=> other.year
48
+ return nil unless self.class === other
49
+ @value <=> other.value
43
50
  end
44
51
 
45
- def - num
46
- self.class[@year - num]
47
- end
52
+ class Year < INat::Report::Period
48
53
 
49
- def to_s
50
- "<i class=\"glyphicon glyphicon-calendar\"></i>  #{ @year }"
51
- end
54
+ class << self
52
55
 
53
- end
56
+ protected def date_to_value date
57
+ date.year
58
+ end
54
59
 
55
- class Month
60
+ end
56
61
 
57
- class << self
62
+ alias :year :value
58
63
 
59
- private :new
64
+ def - num
65
+ self.class[@value - num]
66
+ end
60
67
 
61
- def [] source
62
- return nil if source == nil
63
- return source if Month === source
64
- month = case source
65
- when Date, Time
66
- source.month
67
- when String
68
- date = Date::parse source
69
- date.month
70
- when Integer
71
- source
72
- else
73
- raise TypeError, "Invalid month key: #{ source.inspect }!", caller
74
- end
75
- @months ||= {}
76
- @months[month] ||= new month
77
- @months[month]
68
+ def to_s
69
+ "<i class=\"glyphicon glyphicon-calendar\"></i>  #{ @value } год"
70
+ end
71
+
72
+ def query_params
73
+ "year=#{ @value }"
78
74
  end
79
75
 
80
76
  end
81
77
 
82
- attr_reader :month
78
+ class Month < INat::Report::Period
83
79
 
84
- def initialize month
85
- @month = month
86
- end
80
+ class << self
87
81
 
88
- include Comparable
82
+ protected def date_to_value date
83
+ date.month
84
+ end
89
85
 
90
- def <=> other
91
- return nil unless Month === other
92
- @month <=> other.month
93
- end
86
+ end
94
87
 
95
- end
88
+ alias :month :value
89
+
90
+ NAMES = {
91
+ 1 => 'Январь',
92
+ 2 => 'Февраль',
93
+ 3 => 'Март',
94
+ 4 => 'Апрель',
95
+ 5 => 'Май',
96
+ 6 => 'Июнь',
97
+ 7 => 'Июль',
98
+ 8 => 'Август',
99
+ 9 => 'Сентябрь',
100
+ 10 => 'Октябрь',
101
+ 11 => 'Ноябрь',
102
+ 12 => 'Декабрь'
103
+ }
104
+
105
+ def to_s
106
+ "<i class=\"glyphicon glyphicon-calendar\"></i>  #{ NAMES[@value] }"
107
+ end
96
108
 
97
- class Day
109
+ def query_params
110
+ "month=#{ @value }"
111
+ end
98
112
 
99
- class << self
113
+ end
100
114
 
101
- attr_reader :day
115
+ class Day < INat::Report::Period
102
116
 
103
- def [] source
104
- return nil if source == nil
105
- return source if Day === source
106
- day = case source
107
- when Date, Time
108
- source.day
109
- when String
110
- date = Date::parse source
117
+ class << self
118
+
119
+ protected def date_to_value date
111
120
  date.day
112
- when Integer
113
- source
114
- else
115
- raise TypeError, "Invalid day key: #{ source.inspect }!", caller
116
121
  end
117
- @days ||= {}
118
- @days[day] ||= new day
119
- @days[day]
122
+
120
123
  end
121
124
 
122
- end
125
+ alias :day :value
126
+
127
+ def to_s
128
+ "<i class=\"glyphicon glyphicon-calendar\"></i>  #{ @value }"
129
+ end
123
130
 
124
- attr_reader :day
131
+ def query_params
132
+ "day=#{ @value }"
133
+ end
125
134
 
126
- def initialize day
127
- @day = day
128
135
  end
129
136
 
130
- include Comparable
137
+ class Winter < INat::Report::Period
138
+
139
+ class << self
140
+
141
+ protected def date_to_value date
142
+ month = date.month
143
+ if month <= 4
144
+ date.year
145
+ elsif month >= 10
146
+ date.year + 1
147
+ else
148
+ nil
149
+ end
150
+ end
151
+
152
+ end
153
+
154
+ alias :winter :value
155
+
156
+ def to_s
157
+ "<i class=\"glyphicon glyphicon-calendar\"></i>  Зима #{ @value - 1 }–#{ @value }"
158
+ end
159
+
160
+ def query_params
161
+ "d1=#{ @value - 1 }-10-01&d2=#{ @value }-04-30"
162
+ end
131
163
 
132
- def <=> other
133
- return nil unless Day === other
134
- @day <=> other.day
135
164
  end
136
165
 
137
166
  end