mass_shootings 0.0.1
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.md +20 -0
- data/README.md +39 -0
- data/lib/mass_shootings/gemspec.rb +31 -0
- data/lib/mass_shootings/shooting.rb +38 -0
- data/lib/mass_shootings/tracker/page.rb +86 -0
- data/lib/mass_shootings/tracker.rb +69 -0
- data/lib/mass_shootings/version.rb +6 -0
- data/lib/mass_shootings.rb +8 -0
- data/spec/mass_shootings/tracker_spec.rb +153 -0
- data/spec/spec_helper.rb +6 -0
- metadata +137 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 56342cbde02ebb1f08df1f9eab8957b2827b3156
|
4
|
+
data.tar.gz: 66ff3cb637ac2edd7896673b182c81727b1c2586
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b0c9ad74375a2f5d3bfac7d39413741c285520be7310403db95ce053181f74544cbc1c50398ca3d134aea5fbac8ffed9432e6bd73c574a974acd21fadce64707
|
7
|
+
data.tar.gz: 65353201bda10ce4ec4f32745a9d34212339b176ac769f22a0eb3301ea6e8ec8e6b00b14321eddd19289cbb1abaa7d5b4995bb4f68ccaf3515862f926c4c1301
|
data/LICENSE.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright © 2015 David P. Kleinschmidt
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# mass_shootings
|
2
|
+
|
3
|
+
`mass_shootings` provides an easy-to-use Ruby interface to query and report on
|
4
|
+
mass shootings in America.
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
Mass shootings have several properties:
|
9
|
+
|
10
|
+
- **id** a unique identifier
|
11
|
+
- **alleged_shooters** the names of the alleged shooters, if known
|
12
|
+
- **casualties** count of casualties, classified by type (`:dead` or `:injured`)
|
13
|
+
- **date** date the shooting occurred
|
14
|
+
- **location** where the shooting occurred
|
15
|
+
- **references** links to relevant news sources
|
16
|
+
|
17
|
+
To retrieve a list of mass shootings that occurred within a date range:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
MassShootings::Tracker.in_date_range Date.new(2015, 12, 6)...Date.today + 1
|
21
|
+
```
|
22
|
+
|
23
|
+
To retrieve a single mass shooting by ID:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
MassShootings::Tracker.get '2015-318'
|
27
|
+
```
|
28
|
+
|
29
|
+
You can use Ruby's built-in Enumerable methods to filter results:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
shootings.
|
33
|
+
reject { |shooting| shooting.casualties.fetch(:dead, 0) == 0 }.
|
34
|
+
sort_by { |shooting| shooting.casualties[:dead] }
|
35
|
+
```
|
36
|
+
|
37
|
+
Shootings are cached in-memory. If you use `mass_shooting` in a long-lived
|
38
|
+
process, the cache may become stale unless you call
|
39
|
+
`MassShootings::Tracker.reset` every 24 hours and 36 minutes or so.
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'mass_shootings/version'
|
2
|
+
|
3
|
+
module MassShootings
|
4
|
+
class << self
|
5
|
+
#
|
6
|
+
# Gemspec for `mass_shootings`. This is only used by the gemspec and the
|
7
|
+
# Rakefile, and must be required separately.
|
8
|
+
#
|
9
|
+
def gemspec
|
10
|
+
@gemspec ||= Gem::Specification.new do |gem|
|
11
|
+
gem.authors = 'David P Kleinschmidt'
|
12
|
+
gem.email = 'david@kleinschmidt.name'
|
13
|
+
gem.homepage = 'http://bitbucket.org/zobar/mass_shootings'
|
14
|
+
gem.license = 'MIT'
|
15
|
+
gem.name = 'mass_shootings'
|
16
|
+
gem.summary = 'Mass shootings as a service'
|
17
|
+
gem.version = VERSION
|
18
|
+
|
19
|
+
gem.files = Dir['*.md', '{lib,spec}/**/*.rb']
|
20
|
+
|
21
|
+
gem.add_dependency 'activemodel', '~> 4.2'
|
22
|
+
gem.add_dependency 'nokogiri', '~> 1.6'
|
23
|
+
|
24
|
+
gem.add_development_dependency 'minitest', '~> 5.8'
|
25
|
+
gem.add_development_dependency 'mocha', '~> 1.1'
|
26
|
+
gem.add_development_dependency 'simplecov', '~> 0.11'
|
27
|
+
gem.add_development_dependency 'yard', '~> 0.8'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module MassShootings
|
4
|
+
#
|
5
|
+
# A `MassShooting::Shooting` is when four or more people are shot in an event,
|
6
|
+
# or related series of events, likely without a cooling off period.
|
7
|
+
#
|
8
|
+
class Shooting
|
9
|
+
include ActiveModel::AttributeMethods
|
10
|
+
|
11
|
+
define_attribute_methods :id, :alleged_shooters, :casualties, :date,
|
12
|
+
:location, :references
|
13
|
+
|
14
|
+
#
|
15
|
+
# Retrieves an attribute by name.
|
16
|
+
#
|
17
|
+
def attribute(name)
|
18
|
+
@attributes[name.to_sym]
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Creates a new Shooting with the given attributes.
|
23
|
+
#
|
24
|
+
# @param [Hash] attributes Information pertaining to the Shooting.
|
25
|
+
# @option attributes [String] id a unique identifier
|
26
|
+
# @option attributes [Array<String>] alleged_shooters (nil) the names of the
|
27
|
+
# alleged shooters
|
28
|
+
# @option attributes [Hash{Symbol => Integer}] casualties count of
|
29
|
+
# casualties, classified by type (`:dead` or `:injured`)
|
30
|
+
# @option attributes [Date] date date the shooting occurred
|
31
|
+
# @option attributes [String] location where the shooting occurred
|
32
|
+
# @option attributes [Array<URI>] references links to relevant news sources
|
33
|
+
#
|
34
|
+
def initialize(attributes)
|
35
|
+
@attributes = attributes
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'mass_shootings/shooting'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
module MassShootings
|
6
|
+
module Tracker
|
7
|
+
class Page
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
attr_reader :page_id, :wiki
|
11
|
+
delegate :each, to: :shootings
|
12
|
+
delegate :[], to: :indexed
|
13
|
+
|
14
|
+
def initialize(page_id, data)
|
15
|
+
@page_id = page_id
|
16
|
+
@wiki = Nokogiri::HTML.parse(data).css '.wiki'
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def format
|
22
|
+
@format ||= /\A\s*Number\s*(?<number>.+?):\s*
|
23
|
+
(?<date>.+?),\s*
|
24
|
+
(?<alleged_shooters>.+),\s*
|
25
|
+
(?<casualties>.*?\d.*?),\s*
|
26
|
+
(?<location>.+)\s*\Z/x
|
27
|
+
end
|
28
|
+
|
29
|
+
def indexed
|
30
|
+
@indexed ||= Hash[shootings.map { |shooting| [shooting.id, shooting] }]
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse(elements)
|
34
|
+
h2, as = elements[0], elements[1..-1]
|
35
|
+
|
36
|
+
format.match h2.content do |match|
|
37
|
+
alleged_shooters = parse_alleged_shooters match['alleged_shooters']
|
38
|
+
attributes = {
|
39
|
+
id: "#{page_id}-#{match['number']}",
|
40
|
+
casualties: parse_casualties(match['casualties']),
|
41
|
+
date: parse_date(match['date']),
|
42
|
+
location: match['location'],
|
43
|
+
references: as.map { |a| URI(a[:href]) }
|
44
|
+
}
|
45
|
+
|
46
|
+
if alleged_shooters.any?
|
47
|
+
attributes[:alleged_shooters] = alleged_shooters
|
48
|
+
end
|
49
|
+
|
50
|
+
Shooting.new attributes
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_alleged_shooters(alleged_shooters)
|
55
|
+
alleged_shooters.
|
56
|
+
split(/\s*(?:,?\s+(?:and|&)\s+|[,;](?!\s*Jr\.))\s*/).
|
57
|
+
reject do |shooter|
|
58
|
+
shooter =~ /identified|identity|unnamed|unkn?own|unreported/i
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def parse_casualties(casualties)
|
63
|
+
Hash[
|
64
|
+
casualties.
|
65
|
+
scan(/(\d+)\s+(.+?)\b/).
|
66
|
+
map { |count, type| [type.to_sym, count.to_i] }
|
67
|
+
]
|
68
|
+
end
|
69
|
+
|
70
|
+
def parse_date(date)
|
71
|
+
result = Date.strptime date, '%m/%d/%Y'
|
72
|
+
result.year < 100 ? Date.strptime(date, '%m/%d/%y') : result
|
73
|
+
rescue
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
def shootings
|
78
|
+
@shootings ||= wiki.
|
79
|
+
xpath('child::h2 | child::h2/following-sibling::p/a').
|
80
|
+
slice_before { |element| element.node_name == 'h2' }.
|
81
|
+
map(&method(:parse)).
|
82
|
+
tap { |s| PP.pp s }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'active_support/core_ext/range/overlaps'
|
2
|
+
|
3
|
+
module MassShootings
|
4
|
+
#
|
5
|
+
# Retrieves mass shootings from the [r/GunsAreCool shooting tracker]
|
6
|
+
# (https://www.reddit.com/r/GunsAreCool/wiki/2015massshootings).
|
7
|
+
#
|
8
|
+
module Tracker
|
9
|
+
autoload :Page, 'mass_shootings/tracker/page'
|
10
|
+
private_constant :Page
|
11
|
+
|
12
|
+
class << self
|
13
|
+
#
|
14
|
+
# Retrieves a `Shooting` by unique ID.
|
15
|
+
# @param [String] id the `Shooting`'s unique identifier. This is opaque;
|
16
|
+
# you should not depend on its format.
|
17
|
+
#
|
18
|
+
def get(id)
|
19
|
+
year, number = id.split '-', 2
|
20
|
+
page(year)[id]
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Retrieves all `Shooting`s that occurred within a date range.
|
25
|
+
# @param [Range<Date>] date_range the date range to search. Inclusive and
|
26
|
+
# exclusive ranges are both supported.
|
27
|
+
#
|
28
|
+
def in_date_range(date_range)
|
29
|
+
pages_in_date_range(date_range).
|
30
|
+
map(&method(:page)).
|
31
|
+
flat_map(&:to_a).
|
32
|
+
select { |shooting| date_range.cover? shooting.date }
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Invalidates the in-memory cache. In a long-running process, you should
|
37
|
+
# arrange for this method to be called approximately every 24 hours and 36
|
38
|
+
# minutes.
|
39
|
+
#
|
40
|
+
def reset
|
41
|
+
@pages = {}
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def page(year)
|
47
|
+
pages[year] ||= Page.new year, Net::HTTP.get(uri(year))
|
48
|
+
end
|
49
|
+
|
50
|
+
def pages
|
51
|
+
@pages || reset
|
52
|
+
end
|
53
|
+
|
54
|
+
def pages_in_date_range(date_range)
|
55
|
+
result = []
|
56
|
+
year = date_range.begin.year
|
57
|
+
while date_range.overlaps? Date.new(year, 1, 1)...Date.new(year + 1, 1, 1)
|
58
|
+
result << year.to_s
|
59
|
+
year += 1
|
60
|
+
end
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
64
|
+
def uri(year)
|
65
|
+
URI "https://www.reddit.com/r/GunsAreCool/wiki/#{year}massshootings"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mass_shootings/tracker'
|
3
|
+
|
4
|
+
describe MassShootings::Tracker do
|
5
|
+
let(:alleged_shooters) { ['Alleged Shooter'] }
|
6
|
+
let(:casualties) { {dead: dead, injured: injured} }
|
7
|
+
let(:date) { Date.today }
|
8
|
+
let(:dead) { 1 }
|
9
|
+
let(:injured) { 2 }
|
10
|
+
let(:id) { "#{year}-#{number}" }
|
11
|
+
let(:location_) { 'City, ST' }
|
12
|
+
let(:number) { 1 }
|
13
|
+
let(:reference) { URI('http://example.com/reference') }
|
14
|
+
let(:references) { [reference] }
|
15
|
+
let(:year) { date.year }
|
16
|
+
|
17
|
+
let(:description) do
|
18
|
+
[
|
19
|
+
"Number #{number}: #{date.strftime('%-m/%-d/%Y')}",
|
20
|
+
alleged_shooters.join(' and '),
|
21
|
+
casualties.map { |c| c.reverse.join ' ' }.join(' '),
|
22
|
+
location_
|
23
|
+
].join ', '
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:page) do
|
27
|
+
<<-HTML
|
28
|
+
<!DOCTYPE html>
|
29
|
+
<title></title>
|
30
|
+
<div class='wiki'>
|
31
|
+
<h2>#{description}</h2>
|
32
|
+
<p><a href='#{reference}'>#{reference}</a>
|
33
|
+
</div>
|
34
|
+
HTML
|
35
|
+
end
|
36
|
+
|
37
|
+
let(:uri) do
|
38
|
+
URI "https://www.reddit.com/r/GunsAreCool/wiki/#{year}massshootings"
|
39
|
+
end
|
40
|
+
|
41
|
+
before { Net::HTTP.stubs(:get).with(uri).returns(page) }
|
42
|
+
after { MassShootings::Tracker.reset }
|
43
|
+
|
44
|
+
describe '.get' do
|
45
|
+
subject { MassShootings::Tracker.get id }
|
46
|
+
|
47
|
+
it 'sets the alleged shooter' do
|
48
|
+
subject.alleged_shooters.must_equal alleged_shooters
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'sets the date' do
|
52
|
+
subject.date.must_equal date
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'sets the dead' do
|
56
|
+
subject.casualties[:dead].must_equal dead
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'sets the id' do
|
60
|
+
subject.id.must_equal id
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'sets the injured' do
|
64
|
+
subject.casualties[:injured].must_equal injured
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'sets the location' do
|
68
|
+
subject.location.must_equal location_
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'sets the references' do
|
72
|
+
subject.references.must_equal references
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'with an unknown alleged shooter' do
|
76
|
+
let(:alleged_shooters) { ['Unknown'] }
|
77
|
+
|
78
|
+
it 'does not set the alleged shooter' do
|
79
|
+
subject.alleged_shooters.must_be_nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'with an unidentified alleged shooter' do
|
84
|
+
let(:alleged_shooters) { ['Unidentified'] }
|
85
|
+
|
86
|
+
it 'does not set the alleged shooter' do
|
87
|
+
subject.alleged_shooters.must_be_nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'with two alleged shooters' do
|
92
|
+
let(:alleged_shooters) { ['Alleged', 'Shooter'] }
|
93
|
+
|
94
|
+
it 'sets the alleged shooters' do
|
95
|
+
subject.alleged_shooters.must_equal alleged_shooters
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'with three alleged shooters' do
|
100
|
+
let(:alleged_shooters) { ['Three', 'Alleged', 'Shooters'] }
|
101
|
+
let(:formatted_alleged_shooters) { 'Three, Alleged, and Shooters' }
|
102
|
+
|
103
|
+
it 'sets the alleged shooters' do
|
104
|
+
subject.alleged_shooters.must_equal alleged_shooters
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '.in_date_range' do
|
110
|
+
subject { MassShootings::Tracker.in_date_range date_range }
|
111
|
+
let(:date_2) { date.prev_year }
|
112
|
+
let(:date_range) { from...to }
|
113
|
+
let(:from) { date_2 }
|
114
|
+
let(:id_2) { "#{year_2}-#{number_2}" }
|
115
|
+
let(:number_2) { 7 }
|
116
|
+
let(:to) { date }
|
117
|
+
let(:year_2) { date_2.year }
|
118
|
+
|
119
|
+
let(:description_2) do
|
120
|
+
"Number #{number_2}: #{date_2.strftime('%-m/%-d/%Y')}, Alleged Shooter 2, 11 dead 12 injured, City 2, S2"
|
121
|
+
end
|
122
|
+
|
123
|
+
let(:page_2) do
|
124
|
+
<<-HTML
|
125
|
+
<!DOCTYPE html>
|
126
|
+
<title></title>
|
127
|
+
<div class='wiki'>
|
128
|
+
<h2>#{description_2}</h2>
|
129
|
+
</div>
|
130
|
+
HTML
|
131
|
+
end
|
132
|
+
|
133
|
+
let(:uri_2) do
|
134
|
+
URI "https://www.reddit.com/r/GunsAreCool/wiki/#{year_2}massshootings"
|
135
|
+
end
|
136
|
+
|
137
|
+
before { Net::HTTP.stubs(:get).with(uri_2).returns(page_2) }
|
138
|
+
|
139
|
+
describe 'exclusive' do
|
140
|
+
it 'excludes shootings on the end date' do
|
141
|
+
subject.map(&:id).must_equal [id_2]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'inclusive' do
|
146
|
+
let(:date_range) { from..to }
|
147
|
+
|
148
|
+
it 'includes shootings on the end date' do
|
149
|
+
subject.map(&:id).must_equal [id_2, id]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mass_shootings
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David P Kleinschmidt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mocha
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.11'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.11'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.8'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.8'
|
97
|
+
description:
|
98
|
+
email: david@kleinschmidt.name
|
99
|
+
executables: []
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- LICENSE.md
|
104
|
+
- README.md
|
105
|
+
- lib/mass_shootings.rb
|
106
|
+
- lib/mass_shootings/gemspec.rb
|
107
|
+
- lib/mass_shootings/shooting.rb
|
108
|
+
- lib/mass_shootings/tracker.rb
|
109
|
+
- lib/mass_shootings/tracker/page.rb
|
110
|
+
- lib/mass_shootings/version.rb
|
111
|
+
- spec/mass_shootings/tracker_spec.rb
|
112
|
+
- spec/spec_helper.rb
|
113
|
+
homepage: http://bitbucket.org/zobar/mass_shootings
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.5.0
|
134
|
+
signing_key:
|
135
|
+
specification_version: 4
|
136
|
+
summary: Mass shootings as a service
|
137
|
+
test_files: []
|