inat-get 0.8.0.12 → 0.8.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|