inat-get 0.8.0.12 → 0.8.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +6 -0
- data/bin/inat-get +1 -1
- data/inat-get.gemspec +6 -6
- data/lib/extra/enum.rb +4 -0
- data/lib/extra/period.rb +15 -0
- data/lib/inat/app/application.rb +4 -3
- data/lib/inat/app/config/messagelevel.rb +3 -1
- data/lib/inat/app/config/shiftage.rb +1 -1
- data/lib/inat/app/config/updatemode.rb +1 -1
- data/lib/inat/app/config.rb +6 -2
- data/lib/inat/app/globals.rb +6 -3
- data/lib/inat/app/info.rb +18 -13
- data/lib/inat/app/logging.rb +3 -3
- data/lib/inat/app/preamble.rb +1 -1
- data/lib/inat/app/status.rb +3 -9
- data/lib/inat/app/task/context.rb +8 -4
- data/lib/inat/app/task/dsl.rb +5 -3
- data/lib/inat/app/task.rb +2 -2
- data/lib/inat/data/api.rb +210 -181
- data/lib/inat/data/db.rb +9 -4
- data/lib/inat/data/ddl.rb +24 -5
- data/lib/inat/data/entity/comment.rb +8 -4
- data/lib/inat/data/entity/flag.rb +7 -3
- data/lib/inat/data/entity/identification.rb +9 -4
- data/lib/inat/data/entity/observation.rb +27 -14
- data/lib/inat/data/entity/observationphoto.rb +7 -3
- data/lib/inat/data/entity/observationsound.rb +6 -7
- data/lib/inat/data/entity/photo.rb +9 -3
- data/lib/inat/data/entity/place.rb +11 -2
- data/lib/inat/data/entity/project.rb +16 -10
- data/lib/inat/data/entity/projectadmin.rb +4 -4
- data/lib/inat/data/entity/projectobservationrule.rb +3 -4
- data/lib/inat/data/entity/request.rb +7 -3
- data/lib/inat/data/entity/sound.rb +7 -2
- data/lib/inat/data/entity/taxon.rb +11 -3
- data/lib/inat/data/entity/user.rb +7 -3
- data/lib/inat/data/entity/vote.rb +7 -3
- data/lib/inat/data/entity.rb +38 -24
- data/lib/inat/data/enums/conservationstatus.rb +3 -3
- data/lib/inat/data/enums/geoprivacy.rb +3 -1
- data/lib/inat/data/enums/iconictaxa.rb +1 -1
- data/lib/inat/data/enums/identificationcategory.rb +1 -1
- data/lib/inat/data/enums/licensecode.rb +5 -2
- data/lib/inat/data/enums/projectadminrole.rb +1 -1
- data/lib/inat/data/enums/projecttype.rb +5 -3
- data/lib/inat/data/enums/qualitygrade.rb +1 -1
- data/lib/inat/data/enums/rank.rb +1 -1
- data/lib/inat/data/model.rb +73 -24
- data/lib/inat/data/query.rb +14 -9
- data/lib/inat/data/sets/dataset.rb +9 -5
- data/lib/inat/data/sets/list.rb +8 -3
- data/lib/inat/data/sets/listers.rb +10 -5
- data/lib/inat/data/sets/wrappers.rb +79 -75
- data/lib/inat/data/types/location.rb +17 -8
- data/lib/inat/data/types/std.rb +171 -176
- data/lib/inat/report/report_dsl.rb +13 -11
- data/lib/inat/report/table.rb +7 -3
- data/lib/inat/utils/deep.rb +25 -19
- metadata +5 -5
- data/lib/inat/data/cache.rb +0 -9
data/lib/inat/data/model.rb
CHANGED
@@ -3,12 +3,17 @@
|
|
3
3
|
require_relative '../app/globals'
|
4
4
|
require_relative 'types/std'
|
5
5
|
|
6
|
-
|
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
|
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
|
-
|
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.
|
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.
|
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.
|
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
|
-
|
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.
|
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.
|
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.
|
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
|
-
|
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.
|
301
|
-
link_field = "#{ type.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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?
|
data/lib/inat/data/query.rb
CHANGED
@@ -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
|
-
|
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,7 +3,10 @@
|
|
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
12
|
attr_accessor :object # TODO: переделать select так, чтобы не было необходимости во внешнем присваивании
|
@@ -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
|
data/lib/inat/data/sets/list.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
module INat::Report
|
4
|
+
autoload :DataSet, 'inat/data/sets/dataset'
|
5
|
+
end
|
6
|
+
|
7
|
+
class INat::Report::List
|
4
8
|
|
5
|
-
|
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,15 +2,20 @@
|
|
2
2
|
|
3
3
|
require_relative 'wrappers'
|
4
4
|
|
5
|
-
|
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]
|
13
|
-
WINTER = lambda { |o| Winter[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] }
|
14
19
|
USER = lambda { |o| o.user }
|
15
20
|
|
16
21
|
end
|
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'date'
|
4
4
|
|
5
|
-
|
5
|
+
module INat::Report; end
|
6
|
+
|
7
|
+
# TODO: переделать в модуль namespace и Base-класс отдельно
|
8
|
+
|
9
|
+
class INat::Report::Period
|
6
10
|
|
7
11
|
class << self
|
8
12
|
|
@@ -45,118 +49,118 @@ class Calendarian
|
|
45
49
|
@value <=> other.value
|
46
50
|
end
|
47
51
|
|
48
|
-
|
52
|
+
class Year < INat::Report::Period
|
49
53
|
|
50
|
-
class
|
54
|
+
class << self
|
51
55
|
|
52
|
-
|
56
|
+
protected def date_to_value date
|
57
|
+
date.year
|
58
|
+
end
|
53
59
|
|
54
|
-
protected def date_to_value date
|
55
|
-
date.year
|
56
60
|
end
|
57
61
|
|
58
|
-
|
62
|
+
alias :year :value
|
59
63
|
|
60
|
-
|
64
|
+
def - num
|
65
|
+
self.class[@value - num]
|
66
|
+
end
|
61
67
|
|
62
|
-
|
63
|
-
|
64
|
-
|
68
|
+
def to_s
|
69
|
+
"<i class=\"glyphicon glyphicon-calendar\"></i> #{ @value } год"
|
70
|
+
end
|
65
71
|
|
66
|
-
|
67
|
-
|
68
|
-
|
72
|
+
def query_params
|
73
|
+
"year=#{ @value }"
|
74
|
+
end
|
69
75
|
|
70
|
-
def query_params
|
71
|
-
"year=#{ @value }"
|
72
76
|
end
|
73
77
|
|
74
|
-
|
78
|
+
class Month < INat::Report::Period
|
75
79
|
|
76
|
-
class
|
80
|
+
class << self
|
77
81
|
|
78
|
-
|
82
|
+
protected def date_to_value date
|
83
|
+
date.month
|
84
|
+
end
|
79
85
|
|
80
|
-
protected def date_to_value date
|
81
|
-
date.month
|
82
86
|
end
|
83
87
|
|
84
|
-
|
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
|
85
108
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
1 => 'Январь',
|
90
|
-
2 => 'Февраль',
|
91
|
-
3 => 'Март',
|
92
|
-
4 => 'Апрель',
|
93
|
-
5 => 'Май',
|
94
|
-
6 => 'Июнь',
|
95
|
-
7 => 'Июль',
|
96
|
-
8 => 'Август',
|
97
|
-
9 => 'Сентябрь',
|
98
|
-
10 => 'Октябрь',
|
99
|
-
11 => 'Ноябрь',
|
100
|
-
12 => 'Декабрь'
|
101
|
-
}
|
102
|
-
|
103
|
-
def to_s
|
104
|
-
"<i class=\"glyphicon glyphicon-calendar\"></i> #{ NAMES[@value] }"
|
105
|
-
end
|
109
|
+
def query_params
|
110
|
+
"month=#{ @value }"
|
111
|
+
end
|
106
112
|
|
107
|
-
def query_params
|
108
|
-
"month=#{ @value }"
|
109
113
|
end
|
110
114
|
|
111
|
-
|
115
|
+
class Day < INat::Report::Period
|
112
116
|
|
113
|
-
class
|
117
|
+
class << self
|
114
118
|
|
115
|
-
|
119
|
+
protected def date_to_value date
|
120
|
+
date.day
|
121
|
+
end
|
116
122
|
|
117
|
-
protected def date_to_value date
|
118
|
-
date.day
|
119
123
|
end
|
120
124
|
|
121
|
-
|
125
|
+
alias :day :value
|
122
126
|
|
123
|
-
|
127
|
+
def to_s
|
128
|
+
"<i class=\"glyphicon glyphicon-calendar\"></i> #{ @value }"
|
129
|
+
end
|
124
130
|
|
125
|
-
|
126
|
-
|
127
|
-
|
131
|
+
def query_params
|
132
|
+
"day=#{ @value }"
|
133
|
+
end
|
128
134
|
|
129
|
-
def query_params
|
130
|
-
"day=#{ @value }"
|
131
135
|
end
|
132
136
|
|
133
|
-
|
134
|
-
|
135
|
-
class Winter < Calendarian
|
137
|
+
class Winter < INat::Report::Period
|
136
138
|
|
137
|
-
|
139
|
+
class << self
|
138
140
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
147
150
|
end
|
151
|
+
|
148
152
|
end
|
149
153
|
|
150
|
-
|
154
|
+
alias :winter :value
|
151
155
|
|
152
|
-
|
156
|
+
def to_s
|
157
|
+
"<i class=\"glyphicon glyphicon-calendar\"></i> Зима #{ @value - 1 }–#{ @value }"
|
158
|
+
end
|
153
159
|
|
154
|
-
|
155
|
-
|
156
|
-
|
160
|
+
def query_params
|
161
|
+
"d1=#{ @value - 1 }-10-01&d2=#{ @value }-04-30"
|
162
|
+
end
|
157
163
|
|
158
|
-
def query_params
|
159
|
-
"d1=#{ @value - 1 }-10-01&d2=#{ @value }-04-30"
|
160
164
|
end
|
161
165
|
|
162
166
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
module INat::Data; end
|
4
|
+
module INat::Data::Types; end
|
5
|
+
|
6
|
+
class INat::Data::Types::Location
|
4
7
|
|
5
8
|
class << self
|
6
9
|
|
@@ -53,7 +56,7 @@ class Location
|
|
53
56
|
|
54
57
|
end
|
55
58
|
|
56
|
-
class Radius
|
59
|
+
class INat::Data::Types::Radius
|
57
60
|
|
58
61
|
attr_reader :latitude, :longitude, :radius
|
59
62
|
|
@@ -66,7 +69,7 @@ class Radius
|
|
66
69
|
|
67
70
|
end
|
68
71
|
|
69
|
-
class Sector
|
72
|
+
class INat::Data::Types::Sector
|
70
73
|
|
71
74
|
attr_reader :north, :east, :south, :west
|
72
75
|
|
@@ -80,10 +83,16 @@ class Sector
|
|
80
83
|
|
81
84
|
end
|
82
85
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
+
module INat::Data::Types
|
87
|
+
|
88
|
+
def radius latitude, longitude, radius
|
89
|
+
Radius::new latitude, longitude, radius
|
90
|
+
end
|
91
|
+
|
92
|
+
def sector north, east, south, west
|
93
|
+
Sector::new north, east, south, west
|
94
|
+
end
|
95
|
+
|
96
|
+
module_function :radius, :sector
|
86
97
|
|
87
|
-
def sector north, east, south, west
|
88
|
-
Sector::new north, east, south, west
|
89
98
|
end
|