inat-get 0.8.0.11
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 +7 -0
- data/LICENSE +674 -0
- data/README.md +16 -0
- data/Rakefile +4 -0
- data/bin/inat-get +59 -0
- data/docs/logo.png +0 -0
- data/inat-get.gemspec +33 -0
- data/lib/extra/enum.rb +184 -0
- data/lib/extra/period.rb +252 -0
- data/lib/extra/uuid.rb +90 -0
- data/lib/inat/app/application.rb +50 -0
- data/lib/inat/app/config/messagelevel.rb +22 -0
- data/lib/inat/app/config/shiftage.rb +24 -0
- data/lib/inat/app/config/updatemode.rb +20 -0
- data/lib/inat/app/config.rb +296 -0
- data/lib/inat/app/globals.rb +80 -0
- data/lib/inat/app/info.rb +21 -0
- data/lib/inat/app/logging.rb +35 -0
- data/lib/inat/app/preamble.rb +27 -0
- data/lib/inat/app/status.rb +74 -0
- data/lib/inat/app/task/context.rb +47 -0
- data/lib/inat/app/task/dsl.rb +24 -0
- data/lib/inat/app/task.rb +75 -0
- data/lib/inat/data/api.rb +218 -0
- data/lib/inat/data/cache.rb +9 -0
- data/lib/inat/data/db.rb +87 -0
- data/lib/inat/data/ddl.rb +18 -0
- data/lib/inat/data/entity/comment.rb +29 -0
- data/lib/inat/data/entity/flag.rb +22 -0
- data/lib/inat/data/entity/identification.rb +45 -0
- data/lib/inat/data/entity/observation.rb +172 -0
- data/lib/inat/data/entity/observationphoto.rb +25 -0
- data/lib/inat/data/entity/observationsound.rb +26 -0
- data/lib/inat/data/entity/photo.rb +31 -0
- data/lib/inat/data/entity/place.rb +57 -0
- data/lib/inat/data/entity/project.rb +94 -0
- data/lib/inat/data/entity/projectadmin.rb +21 -0
- data/lib/inat/data/entity/projectobservationrule.rb +50 -0
- data/lib/inat/data/entity/request.rb +58 -0
- data/lib/inat/data/entity/sound.rb +27 -0
- data/lib/inat/data/entity/taxon.rb +94 -0
- data/lib/inat/data/entity/user.rb +67 -0
- data/lib/inat/data/entity/vote.rb +22 -0
- data/lib/inat/data/entity.rb +291 -0
- data/lib/inat/data/enums/conservationstatus.rb +30 -0
- data/lib/inat/data/enums/geoprivacy.rb +14 -0
- data/lib/inat/data/enums/iconictaxa.rb +23 -0
- data/lib/inat/data/enums/identificationcategory.rb +13 -0
- data/lib/inat/data/enums/licensecode.rb +16 -0
- data/lib/inat/data/enums/projectadminrole.rb +11 -0
- data/lib/inat/data/enums/projecttype.rb +37 -0
- data/lib/inat/data/enums/qualitygrade.rb +12 -0
- data/lib/inat/data/enums/rank.rb +60 -0
- data/lib/inat/data/model.rb +551 -0
- data/lib/inat/data/query.rb +1145 -0
- data/lib/inat/data/sets/dataset.rb +104 -0
- data/lib/inat/data/sets/list.rb +190 -0
- data/lib/inat/data/sets/listers.rb +15 -0
- data/lib/inat/data/sets/wrappers.rb +137 -0
- data/lib/inat/data/types/extras.rb +88 -0
- data/lib/inat/data/types/location.rb +89 -0
- data/lib/inat/data/types/std.rb +293 -0
- data/lib/inat/report/table.rb +135 -0
- data/lib/inat/utils/deep.rb +30 -0
- metadata +137 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'listers'
|
4
|
+
require_relative 'list'
|
5
|
+
|
6
|
+
class DataSet
|
7
|
+
|
8
|
+
attr_reader :time
|
9
|
+
attr_reader :object
|
10
|
+
attr_reader :observations
|
11
|
+
|
12
|
+
def initialize object, observations, time: Time::new
|
13
|
+
@object = object
|
14
|
+
@time = time
|
15
|
+
@observations = observations.sort_by { |o| o.sort_key }.uniq
|
16
|
+
@sorted = true
|
17
|
+
@by_id = {}
|
18
|
+
@observations.each do |o|
|
19
|
+
@by_id[o.id] = o
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.zero
|
24
|
+
new nil, []
|
25
|
+
end
|
26
|
+
|
27
|
+
include Enumerable
|
28
|
+
|
29
|
+
def each
|
30
|
+
if block_given?
|
31
|
+
@observations.sort_by! { |o| o.sort_key } unless @sorted
|
32
|
+
@sorted = true
|
33
|
+
@observations.each do |o|
|
34
|
+
yield o
|
35
|
+
end
|
36
|
+
else
|
37
|
+
to_enum :each
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def reverse_each
|
42
|
+
if block_given?
|
43
|
+
@observations.sort_by! { |o| o.sort_key } unless @sorted
|
44
|
+
@sorted = true
|
45
|
+
@observations.reverse_each do |o|
|
46
|
+
yield o
|
47
|
+
end
|
48
|
+
else
|
49
|
+
to_enum :reverse_each
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def count
|
54
|
+
@observations.size
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_list lister = Listers::SPECIES, sorter: nil
|
58
|
+
List::new self, lister, sorter: sorter, time: @time
|
59
|
+
end
|
60
|
+
|
61
|
+
def include? observation
|
62
|
+
@by_id.has_key? observation.id
|
63
|
+
end
|
64
|
+
|
65
|
+
def empty?
|
66
|
+
@observations.empty?
|
67
|
+
end
|
68
|
+
|
69
|
+
def where &block
|
70
|
+
raise ArgumentError, "Block must be provided!", caller unless block_given?
|
71
|
+
DataSet::new nil, @observations.select(&block), time: @time
|
72
|
+
end
|
73
|
+
|
74
|
+
alias :=== :include?
|
75
|
+
|
76
|
+
def << observation
|
77
|
+
raise TypeError, "Argument must be an Observation (#{ observation.inspect })!" unless Observation === observation
|
78
|
+
if !self.include?(observation)
|
79
|
+
@observations << observation
|
80
|
+
@by_id[observation.id] = observation
|
81
|
+
@sorted = false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def | other
|
86
|
+
obj = @object == other.object ? @object : nil
|
87
|
+
DataSet::new obj, @observations + other.observations, time: Time::new
|
88
|
+
end
|
89
|
+
|
90
|
+
def & other
|
91
|
+
obj = @object == other.object ? @object : nil
|
92
|
+
DataSet::new obj, @observations.select { |o| other.include?(o) }, time: Time::new
|
93
|
+
end
|
94
|
+
|
95
|
+
def - other
|
96
|
+
obj = @object == other.object ? @object : nil
|
97
|
+
DataSet::new obj, @observations.select { |o| !other.include?(o) }, time: Time::new
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_a
|
101
|
+
@observations.dup
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
autoload :DataSet, 'inat/data/sets/dataset'
|
4
|
+
|
5
|
+
class List
|
6
|
+
|
7
|
+
attr_reader :lister, :sorter
|
8
|
+
|
9
|
+
DEFAULT_SORTER = lambda { |ds| ds.object.respond_to?(:sort_key) ? ds.object.sort_key : ds.object }
|
10
|
+
|
11
|
+
def initialize source, lister, sorter: nil, time: Time::new
|
12
|
+
@lister = lister
|
13
|
+
@sorter = sorter || DEFAULT_SORTER
|
14
|
+
@time = time
|
15
|
+
@data = {}
|
16
|
+
source.each do |observation|
|
17
|
+
key = @lister.call observation
|
18
|
+
if key != nil
|
19
|
+
@data[key] ||= DataSet::new key, [], time: @time
|
20
|
+
@data[key] << observation
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.zero lister = Listers::SPECIES
|
26
|
+
new [], lister
|
27
|
+
end
|
28
|
+
|
29
|
+
include Enumerable
|
30
|
+
|
31
|
+
def [] key
|
32
|
+
@data[key]
|
33
|
+
end
|
34
|
+
|
35
|
+
def each
|
36
|
+
if block_given?
|
37
|
+
@data.values.sort_by { |ds| @sorter.call(ds) }.each do |ds|
|
38
|
+
yield ds
|
39
|
+
end
|
40
|
+
else
|
41
|
+
to_enum :each
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_dataset
|
46
|
+
observations = []
|
47
|
+
@data.values.each do |ds|
|
48
|
+
observations += ds.observations
|
49
|
+
end
|
50
|
+
DataSet::new nil, observations, time: @time
|
51
|
+
end
|
52
|
+
|
53
|
+
def include? key
|
54
|
+
@data.has_key? key
|
55
|
+
end
|
56
|
+
|
57
|
+
def empty?
|
58
|
+
@data.empty?
|
59
|
+
end
|
60
|
+
|
61
|
+
def count
|
62
|
+
@data.size
|
63
|
+
end
|
64
|
+
|
65
|
+
def observation_count
|
66
|
+
@data.values.map { |ds| ds.count }.sum
|
67
|
+
end
|
68
|
+
|
69
|
+
def where &block
|
70
|
+
raise ArgumentError, "Block must be provided!", caller unless block_given?
|
71
|
+
result = List::new [], @lister, sorter: @sorter, time: @time
|
72
|
+
self.each do |ds|
|
73
|
+
result << ds if yield(ds)
|
74
|
+
end
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
def << some
|
79
|
+
case some
|
80
|
+
when Observation
|
81
|
+
key = @lister.call some
|
82
|
+
if key != nil
|
83
|
+
@data[key] ||= DataSet::new key, [], time: @time
|
84
|
+
@data[key] << some
|
85
|
+
end
|
86
|
+
when DataSet
|
87
|
+
if !some.empty?
|
88
|
+
valid = some.object != nil && some.all? { |o| @lister.call(o) == some.object }
|
89
|
+
if valid
|
90
|
+
if @data[some.object]
|
91
|
+
@data[some.object] = @data[some.object] | some
|
92
|
+
else
|
93
|
+
@data[some.object] = some
|
94
|
+
end
|
95
|
+
else
|
96
|
+
some.each do |o|
|
97
|
+
self << o
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
when Array
|
102
|
+
some.each do |o|
|
103
|
+
self << o
|
104
|
+
end
|
105
|
+
else
|
106
|
+
raise TypeError, "Can not add this object: #{ some.inspect }!", caller
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
alias :=== :include?
|
111
|
+
|
112
|
+
def cover? other
|
113
|
+
other.any? { |ds| self.include?(ds.object) }
|
114
|
+
end
|
115
|
+
|
116
|
+
include Comparable
|
117
|
+
|
118
|
+
def <=> other
|
119
|
+
return nil unless List === other
|
120
|
+
if self.cover?(other)
|
121
|
+
if other.cover?(self)
|
122
|
+
return 0
|
123
|
+
else
|
124
|
+
return 1
|
125
|
+
end
|
126
|
+
else
|
127
|
+
if other.cover?(self)
|
128
|
+
return -1
|
129
|
+
else
|
130
|
+
return nil
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def apply! *data
|
136
|
+
@lister, @sorter, @time, @data = data
|
137
|
+
self
|
138
|
+
end
|
139
|
+
|
140
|
+
def clone
|
141
|
+
List::zero.apply! @lister, @sorter, @time, @data.dup
|
142
|
+
end
|
143
|
+
|
144
|
+
def add! other
|
145
|
+
other.each do |ds|
|
146
|
+
self << ds
|
147
|
+
end
|
148
|
+
self
|
149
|
+
end
|
150
|
+
|
151
|
+
def mul! other
|
152
|
+
@data.delete_if { | key, _ | !other.include?(key) }
|
153
|
+
other.each do |ds|
|
154
|
+
if self.include?(ds.object)
|
155
|
+
self << ds
|
156
|
+
end
|
157
|
+
end
|
158
|
+
self
|
159
|
+
end
|
160
|
+
|
161
|
+
def sub! other
|
162
|
+
@data.delete_if { | key, _ | other.include?(key) }
|
163
|
+
self
|
164
|
+
end
|
165
|
+
|
166
|
+
def add other
|
167
|
+
clone.add! other
|
168
|
+
end
|
169
|
+
|
170
|
+
def mul other
|
171
|
+
# А вот здесь будет эффективней старое решение
|
172
|
+
result = List::new [], @lister, sorter: @sorter, time: @time
|
173
|
+
@data.each do |key, ds|
|
174
|
+
if other.include?(key)
|
175
|
+
summa = ds | other[key]
|
176
|
+
self << summa
|
177
|
+
end
|
178
|
+
end
|
179
|
+
result
|
180
|
+
end
|
181
|
+
|
182
|
+
def sub other
|
183
|
+
clone.sub! other
|
184
|
+
end
|
185
|
+
|
186
|
+
alias :+ :add
|
187
|
+
alias :* :mul
|
188
|
+
alias :- :sub
|
189
|
+
|
190
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'wrappers'
|
4
|
+
|
5
|
+
module Listers
|
6
|
+
|
7
|
+
SPECIES = lambda { |o| o.normalized_taxon(Rank::COMPLEX .. Rank::HYBRID) }
|
8
|
+
GENUS = lambda { |o| o.normalized_taxon(Rank::GENUS) }
|
9
|
+
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
|
+
USER = lambda { |o| o.user }
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
class Year
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
private :new
|
10
|
+
|
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
|
17
|
+
when String
|
18
|
+
date = Date::parse source
|
19
|
+
date.year
|
20
|
+
when Integer
|
21
|
+
source
|
22
|
+
else
|
23
|
+
raise TypeError, "Invalid year key: #{ source.inspect }!", caller
|
24
|
+
end
|
25
|
+
@years ||= {}
|
26
|
+
@years[year] ||= new year
|
27
|
+
@years[year]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :year
|
33
|
+
|
34
|
+
def initialize year
|
35
|
+
@year = year
|
36
|
+
end
|
37
|
+
|
38
|
+
include Comparable
|
39
|
+
|
40
|
+
def <=> other
|
41
|
+
return nil unless Year === other
|
42
|
+
@year <=> other.year
|
43
|
+
end
|
44
|
+
|
45
|
+
def - num
|
46
|
+
self.class[@year - num]
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
"<i class=\"glyphicon glyphicon-calendar\"></i> #{ @year }"
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
class Month
|
56
|
+
|
57
|
+
class << self
|
58
|
+
|
59
|
+
private :new
|
60
|
+
|
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]
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
attr_reader :month
|
83
|
+
|
84
|
+
def initialize month
|
85
|
+
@month = month
|
86
|
+
end
|
87
|
+
|
88
|
+
include Comparable
|
89
|
+
|
90
|
+
def <=> other
|
91
|
+
return nil unless Month === other
|
92
|
+
@month <=> other.month
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
class Day
|
98
|
+
|
99
|
+
class << self
|
100
|
+
|
101
|
+
attr_reader :day
|
102
|
+
|
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
|
111
|
+
date.day
|
112
|
+
when Integer
|
113
|
+
source
|
114
|
+
else
|
115
|
+
raise TypeError, "Invalid day key: #{ source.inspect }!", caller
|
116
|
+
end
|
117
|
+
@days ||= {}
|
118
|
+
@days[day] ||= new day
|
119
|
+
@days[day]
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
attr_reader :day
|
125
|
+
|
126
|
+
def initialize day
|
127
|
+
@day = day
|
128
|
+
end
|
129
|
+
|
130
|
+
include Comparable
|
131
|
+
|
132
|
+
def <=> other
|
133
|
+
return nil unless Day === other
|
134
|
+
@day <=> other.day
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'extra/enum'
|
4
|
+
require 'extra/uuid'
|
5
|
+
|
6
|
+
class Enum
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
pre_verbose = $VERBOSE
|
11
|
+
$VERBOSE = nil
|
12
|
+
|
13
|
+
alias :old_parse :parse
|
14
|
+
|
15
|
+
def parse src
|
16
|
+
return nil if src == nil
|
17
|
+
return src if self === src
|
18
|
+
case src
|
19
|
+
when Integer, Symbol
|
20
|
+
self[src]
|
21
|
+
when String
|
22
|
+
self.old_parse src, case_sensitive: false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
$VERBOSE = pre_verbose
|
27
|
+
|
28
|
+
def ddl
|
29
|
+
if any? { |v| Integer === v.data }
|
30
|
+
{
|
31
|
+
name: :TEXT,
|
32
|
+
data: :INTEGER
|
33
|
+
}
|
34
|
+
else
|
35
|
+
:TEXT
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def from_db src
|
40
|
+
return nil if src == nil
|
41
|
+
return self[src.intern] if String === src || Symbol === src
|
42
|
+
name = src[:name]&.intern
|
43
|
+
return nil if name == nil
|
44
|
+
self[name]
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_db
|
50
|
+
if self.class.any? { |v| Integer === v.data }
|
51
|
+
{
|
52
|
+
name: name.to_s,
|
53
|
+
data: data
|
54
|
+
}
|
55
|
+
else
|
56
|
+
name.to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_query
|
61
|
+
to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
class UUID
|
67
|
+
|
68
|
+
class << self
|
69
|
+
|
70
|
+
def ddl
|
71
|
+
:TEXT
|
72
|
+
end
|
73
|
+
|
74
|
+
def from_db src
|
75
|
+
parse src
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_db
|
81
|
+
to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_query
|
85
|
+
to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Location
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def parse src
|
8
|
+
case src
|
9
|
+
when nil
|
10
|
+
nil
|
11
|
+
when String
|
12
|
+
parse src.split(',').map(&:to_f)
|
13
|
+
when Array
|
14
|
+
new(src[0], src[1]).freeze
|
15
|
+
when Hash
|
16
|
+
latitude = src[:latitude] || src['latitude']
|
17
|
+
longitude = src[:longitude] || src['longitude']
|
18
|
+
return nil if latitude == nil && longitude == nil
|
19
|
+
new(latitude, longitude).freeze
|
20
|
+
else
|
21
|
+
raise ArgumentError, "Source must be a String or Array or Hash!", caller
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def from_db src
|
26
|
+
new(src[:latitude] || src['latitude'], src[:longitude] || src['longitude']).freeze
|
27
|
+
end
|
28
|
+
|
29
|
+
def ddl
|
30
|
+
{
|
31
|
+
latitude: :REAL,
|
32
|
+
longitude: :REAL
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :latitude, :longitude
|
39
|
+
|
40
|
+
def initialize latitude, longitude
|
41
|
+
raise ArgumentError, "Latitude must be a Numeric!", caller unless Numeric === latitude || latitude == nil
|
42
|
+
raise ArgumentError, "Longitude must be a Numeric!", caller unless Numeric === longitude || latitude == nil
|
43
|
+
@latitude = latitude
|
44
|
+
@longitude = longitude
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_db
|
48
|
+
{
|
49
|
+
latitude: latitude,
|
50
|
+
longitude: longitude
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
class Radius
|
57
|
+
|
58
|
+
attr_reader :latitude, :longitude, :radius
|
59
|
+
|
60
|
+
def initialize latitude, longitude, radius
|
61
|
+
raise ArgumentError, "Latitude must be a Numeric!", caller unless Numeric === latitude
|
62
|
+
raise ArgumentError, "Longitude must be a Numeric!", caller unless Numeric === longitude
|
63
|
+
raise ArgumentError, "Radius must be a Numeric!", caller unless Numeric === radius || radius == nil
|
64
|
+
@latitude, @longitude, @radius = latitude, longitude, radius
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
class Sector
|
70
|
+
|
71
|
+
attr_reader :north, :east, :south, :west
|
72
|
+
|
73
|
+
def initialize north, east, south, west
|
74
|
+
raise ArgumentError, "North must be a Numeric!", caller unless Numeric === north
|
75
|
+
raise ArgumentError, "East must be a Numeric!", caller unless Numeric === east
|
76
|
+
raise ArgumentError, "South must be a Numeric!", caller unless Numeric === south
|
77
|
+
raise ArgumentError, "West must be a Numeric!", caller unless Numeric === west
|
78
|
+
@north, @east, @south, @west = north, east, south, west
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
def radius latitude, longitude, radius
|
84
|
+
Radius::new latitude, longitude, radius
|
85
|
+
end
|
86
|
+
|
87
|
+
def sector north, east, south, west
|
88
|
+
Sector::new north, east, south, west
|
89
|
+
end
|