fcc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2-head@fccc
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+
9
+ gem "nokogiri"
10
+
11
+ group :development do
12
+ gem "shoulda", ">= 0"
13
+ gem "bundler", "~> 1.0.0"
14
+ gem "jeweler", "~> 1.5.2"
15
+ gem "rcov", ">= 0"
16
+ end
@@ -0,0 +1,22 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.5.2)
6
+ bundler (~> 1.0.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ nokogiri (1.4.4)
10
+ rake (0.8.7)
11
+ rcov (0.9.9)
12
+ shoulda (2.11.3)
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ bundler (~> 1.0.0)
19
+ jeweler (~> 1.5.2)
20
+ nokogiri
21
+ rcov
22
+ shoulda
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Jeff Keen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ = fcc
2
+
3
+ Queries the FCC database for FM information.
4
+
5
+ FCC::FM.find("KUT") #=> KUT station info
6
+
7
+ FCC::AM.find("KLBJ") #=> KLBJ station info
8
+
9
+ FCC::FM.find_all(:city => "Austin", :state => "TX") #=> [FM::Station, FM::Station, FM::Station]
10
+
11
+
12
+ TODO: Dry some of this out.
13
+
14
+ == Contributing to fcc
15
+
16
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
17
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
18
+ * Fork the project
19
+ * Start a feature/bugfix branch
20
+ * Commit and push until you are happy with your contribution
21
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
22
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
23
+
24
+ == Copyright
25
+
26
+ Copyright (c) 2011 Jeff Keen. See LICENSE.txt for
27
+ further details.
28
+
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "fcc"
16
+ gem.homepage = "http://github.com/jkeen/fcc"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Searches the FCC's FM and AM databases}
19
+ gem.description = %Q{}
20
+ gem.email = "jeff@keen.me"
21
+ gem.authors = ["Jeff Keen"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/test_*.rb'
40
+ test.verbose = true
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "fcc #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,126 @@
1
+ require 'open-uri'
2
+
3
+ module FCC
4
+ class AM
5
+ class Station
6
+ attr_reader :call_letters, :band, :hours, :file_number, :station_class, :fcc_id, :city, :state, :country, :licensed_to, :latitude, :longitude
7
+ def initialize(*fields)
8
+ @raw = fields
9
+ @call_letters = fields[0]
10
+ @frequency = fields[1]
11
+ @band = fields[2]
12
+ # fields[3] # Not used for AM
13
+ # fields[4] # Directional Antenna (DA) or NonDirectional (ND)
14
+ @hours = fields[5] # Hours of operation for this record (daytime, nighttime, or unlimited)
15
+ @domestic_class = fields[6] # Domestic US Station class
16
+ @international_class =fields[7] # International station class
17
+ @fm_status = fields[8]
18
+ @city = fields[9]
19
+ @state = fields[10]
20
+ @country = fields[11]
21
+ @file_number = fields[12] # File Number (Application, Construction Permit or License) or Docket Number (Rulemaking)
22
+ @signal_strength = fields[13] # Power
23
+ # fields[14] # Not used
24
+ # fields[15] # Not used
25
+ # fields[16] # Not used
26
+ @fcc_id = fields[17] # Facility ID Number (unique to each station)
27
+ @latitude = latitude(fields[18], fields[19], fields[20], fields[21])
28
+ @longitude = longitude(fields[22], fields[23], fields[24], fields[25])
29
+
30
+ @licensed_to = fields[26] # Licensee or Permittee
31
+ # fields[27] # Kilometers distant (radius) from entered latitude, longitude
32
+ # fields[28] # Miles distant (radius) from entered latitude, longitude
33
+ # fields[29] # Azimuth, looking from center Lat, Lon to this record's Lat, Lon
34
+ # fields[30] # Application ID number (from CDBS database)***
35
+ end
36
+
37
+ private
38
+
39
+ def longitude(direction, degrees, minutes, seconds)
40
+ "#{(direction =~ /S/ ? "-" : "")}#{degrees}.#{minutes}"
41
+ end
42
+
43
+ def latitude(direction, degrees, minutes, seconds)
44
+ "#{(direction =~ /S/ ? "-" : "")}#{degrees}.#{minutes}"
45
+ end
46
+
47
+ def signal_strength(raw_signal)
48
+ raw_signal.gsub(/\.\s+/, ".0 ") if raw_signal
49
+ end
50
+
51
+ def frequency(freq)
52
+ freq[/[0-9]+\.?[0-9]/] if freq
53
+ end
54
+ end
55
+
56
+ BASE_URL = "http://www.fcc.gov/fcc-bin/amq"
57
+
58
+ def self.find(call_letters)
59
+ raise ArgumentError, "no call letters were supplied" if call_letters.nil? || call_letters.strip.length == 0
60
+
61
+ find_all(:call_letters => call_letters).first
62
+ end
63
+
64
+ def self.find_all(conditions = {})
65
+ results = []
66
+ query(conditions.merge(:band => "AM")) do |feed|
67
+ feed.each_line do |row|
68
+ fields = row.split("|").select { |field| (field.strip! && !field.nil?)}
69
+ results << Station.new(*fields)
70
+ end
71
+ end
72
+ # if call letters are supplied, return matches that match call letters exactly.
73
+ # FCC does partial matches (from the start of the string), so that "KUT" will return "KUTT", also
74
+ if conditions[:call_letters]
75
+ exact_matches = results.select { |d| d.call_letters == conditions[:call_letters] }
76
+ results = exact_matches if (exact_matches)
77
+ end
78
+
79
+ #sort by signal strength
80
+ if results.size > 1
81
+ results.sort_by { |s| s.signal_strength}.reverse
82
+ else
83
+ results
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def self.query(conditions = {})
90
+ query = ""
91
+ prepare_args(conditions).each { |k,v| query += "#{k}=#{v}&" }
92
+ url = "#{BASE_URL}?#{query}"
93
+ feed = open(url)
94
+ yield feed
95
+ end
96
+
97
+ def self.prepare_args(params)
98
+ return {
99
+ :state => params[:state],
100
+ :call => params[:call_letters],
101
+ :city => params[:city],
102
+ :arn => nil,
103
+ :serv => params[:band],
104
+ :vac => nil,
105
+ :freq => params[:frequency] || params[:frequency_lower] || "530",
106
+ :fre2 => params[:frequency] || params[:frequency_upper] || "1700",
107
+ :facid => nil,
108
+ :class => nil,
109
+ :dkt => nil,
110
+ :dist => nil,
111
+ :dlat2 => nil,
112
+ :dlon2 => nil,
113
+ :mlon2 => nil,
114
+ :mlat2 => nil,
115
+ :slat2 => nil,
116
+ :slon2 => nil,
117
+ # :NS => "N",
118
+ # :e => 9,
119
+ :EW => "W",
120
+ :list => 4, # pipe separated output
121
+ :size => 9
122
+ }
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,3 @@
1
+ require 'open-uri'
2
+ require 'fm'
3
+ require 'am'
@@ -0,0 +1,144 @@
1
+ require 'open-uri'
2
+
3
+ module FCC
4
+ class FM
5
+ class Station
6
+ attr_reader :call_letters, :band, :channel, :fm_status, :latitude, :longitude, :file_number, :station_class, :fcc_id, :city, :state, :country, :licensed_to
7
+ def initialize(*fields)
8
+ @raw = fields
9
+ @call_letters = fields[0]
10
+ @frequency = frequency(fields[1])
11
+ @band = fields[2]
12
+ @channel = fields[3]
13
+ # fields[4] # Directional Antenna (DA) or NonDirectional (ND)
14
+ # fields[5] # (Not Used for FM)
15
+ @station_class = fields[6]
16
+ # fields[7] # (Not Used for FM)
17
+ @fm_status = fields[8]
18
+ @city = fields[9]
19
+ @state = fields[10]
20
+ @country = fields[11]
21
+ @file_number = fields[12] # File Number (Application, Construction Permit or License) or Docket Number (Rulemaking)
22
+ @signal_strength = signal_strength(fields[13]) # Effective Radiated Power -- horizontally polarized (maximum)
23
+ # fields[14] # Effective Radiated Power -- vertically polarized (maximum)
24
+ # fields[15] # Antenna Height Above Average Terrain (HAAT) -- horizontal polarization
25
+ # fields[16] # Antenna Height Above Average Terrain (HAAT) -- vertical polarization
26
+ @fcc_id = fields[17] # Facility ID Number (unique to each station)
27
+
28
+ @latitude = latitude(fields[18], fields[19], fields[20], fields[21])
29
+ @longitude = longitude(fields[22], fields[23], fields[24], fields[25])
30
+
31
+ @licensed_to = fields[26] # Licensee or Permittee
32
+ # fields[27] # Kilometers distant (radius) from entered latitude, longitude
33
+ # fields[28] # Miles distant (radius) from entered latitude, longitude
34
+ # fields[29] # Azimuth, looking from center Lat, Lon to this record's Lat, Lon
35
+ # fields[30] # Antenna Radiation Center Above Mean Sea Level (RCAMSL) - Horizontally Polarized - meters
36
+ # fields[31] # Antenna Radiation Center Above Mean Sea Level (RCAMSL) - Vertically Polarized - meters
37
+ # fields[32] # Directional Antenna ID Number
38
+ # fields[33] # Directional Antenna Pattern Rotation (degrees)
39
+ # fields[34] # Antenna Structure Registration Number
40
+ # fields[35] # Application ID number (from CDBS database)***
41
+ end
42
+
43
+ def good?
44
+ return false if @call_letters == "NEW"
45
+ return false if @call_letters == "-"
46
+ return false if @band != "FM"
47
+ #@call_letters =~ /^[^0-9]/
48
+
49
+ true
50
+ end
51
+
52
+ private
53
+
54
+ def longitude(direction, degrees, minutes, seconds)
55
+ "#{(direction =~ /S/ ? "-" : "")}#{degrees}.#{minutes}"
56
+ end
57
+
58
+ def latitude(direction, degrees, minutes, seconds)
59
+ "#{(direction =~ /S/ ? "-" : "")}#{degrees}.#{minutes}"
60
+ end
61
+
62
+ def signal_strength(raw_signal)
63
+ raw_signal.gsub(/\.\s+/, ".0 ") if raw_signal
64
+ end
65
+
66
+ def frequency(freq)
67
+ freq[/[0-9]+\.?[0-9]/] if freq
68
+ end
69
+ end
70
+
71
+ BASE_URL = "http://www.fcc.gov/fcc-bin/fmq"
72
+
73
+ def self.find(call_letters)
74
+ raise ArgumentError, "no call letters were supplied" if call_letters.nil? || call_letters.strip.length == 0
75
+
76
+ find_all(:call_letters => call_letters).first
77
+ end
78
+
79
+ def self.find_all(conditions = {})
80
+ results = []
81
+ query(conditions.merge(:band => "FM")) do |feed|
82
+ feed.each_line do |row|
83
+ fields = row.split("|").select { |field| (field.strip! && !field.nil?)}
84
+ results << Station.new(*fields)
85
+ end
86
+ end
87
+ #remove invalid values, such as "NEW", or "-", stations starting with numbers, and non-FM bands
88
+ results = results.select(&:good?)
89
+ # if call letters are supplied, return matches that match call letters exactly.
90
+ # FCC does a starts_with search, so that "KUT" will return "KUTT", also
91
+ if conditions[:call_letters]
92
+ exact_matches = results.select { |d| d.call_letters == conditions[:call_letters] }
93
+ results = exact_matches if (exact_matches)
94
+ end
95
+
96
+ results
97
+ #sort by signal strength
98
+ if results.size > 1
99
+ results.sort_by { |s| s.signal_strength}.reverse
100
+ else
101
+ results
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def self.query(conditions = {})
108
+ query = ""
109
+ prepare_args(conditions).each { |k,v| query += "#{k}=#{v}&" }
110
+ url = "#{BASE_URL}?#{query}"
111
+ feed = open(url)
112
+ yield feed
113
+ end
114
+
115
+ def self.prepare_args(params)
116
+ return {
117
+ :state => params[:state],
118
+ :call => params[:call_letters],
119
+ :city => params[:city],
120
+ :arn => nil,
121
+ :serv => params[:band],
122
+ :vac => nil,
123
+ :freq => params[:frequency] || params[:frequency_lower] || "0.0",
124
+ :fre2 => params[:frequency] || params[:frequency_upper] || "108.0",
125
+ :facid => nil,
126
+ :class => nil,
127
+ :dkt => nil,
128
+ :dist => nil,
129
+ :dlat2 => nil,
130
+ :dlon2 => nil,
131
+ :mlon2 => nil,
132
+ :mlat2 => nil,
133
+ :slat2 => nil,
134
+ :slon2 => nil,
135
+ # :NS => "N",
136
+ # :e => 9,
137
+ :EW => "W",
138
+ :list => 4, # pipe separated output
139
+ :size => 9
140
+ }
141
+ end
142
+
143
+ end
144
+ end
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'fcc'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestFcc < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fcc
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Jeff Keen
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-30 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ requirement: *id001
32
+ prerelease: false
33
+ name: nokogiri
34
+ type: :runtime
35
+ - !ruby/object:Gem::Dependency
36
+ version_requirements: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ hash: 3
42
+ segments:
43
+ - 0
44
+ version: "0"
45
+ requirement: *id002
46
+ prerelease: false
47
+ name: shoulda
48
+ type: :development
49
+ - !ruby/object:Gem::Dependency
50
+ version_requirements: &id003 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ hash: 23
56
+ segments:
57
+ - 1
58
+ - 0
59
+ - 0
60
+ version: 1.0.0
61
+ requirement: *id003
62
+ prerelease: false
63
+ name: bundler
64
+ type: :development
65
+ - !ruby/object:Gem::Dependency
66
+ version_requirements: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ~>
70
+ - !ruby/object:Gem::Version
71
+ hash: 7
72
+ segments:
73
+ - 1
74
+ - 5
75
+ - 2
76
+ version: 1.5.2
77
+ requirement: *id004
78
+ prerelease: false
79
+ name: jeweler
80
+ type: :development
81
+ - !ruby/object:Gem::Dependency
82
+ version_requirements: &id005 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirement: *id005
92
+ prerelease: false
93
+ name: rcov
94
+ type: :development
95
+ description: ""
96
+ email: jeff@keen.me
97
+ executables: []
98
+
99
+ extensions: []
100
+
101
+ extra_rdoc_files:
102
+ - LICENSE.txt
103
+ - README.rdoc
104
+ files:
105
+ - .document
106
+ - .rvmrc
107
+ - Gemfile
108
+ - Gemfile.lock
109
+ - LICENSE.txt
110
+ - README.rdoc
111
+ - Rakefile
112
+ - VERSION
113
+ - lib/am.rb
114
+ - lib/fcc.rb
115
+ - lib/fm.rb
116
+ - test/helper.rb
117
+ - test/test_fcc.rb
118
+ has_rdoc: true
119
+ homepage: http://github.com/jkeen/fcc
120
+ licenses:
121
+ - MIT
122
+ post_install_message:
123
+ rdoc_options: []
124
+
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ hash: 3
133
+ segments:
134
+ - 0
135
+ version: "0"
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ hash: 3
142
+ segments:
143
+ - 0
144
+ version: "0"
145
+ requirements: []
146
+
147
+ rubyforge_project:
148
+ rubygems_version: 1.4.1
149
+ signing_key:
150
+ specification_version: 3
151
+ summary: Searches the FCC's FM and AM databases
152
+ test_files:
153
+ - test/helper.rb
154
+ - test/test_fcc.rb