Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
dwilkie committed Oct 5, 2024
1 parent 97cf4c8 commit 57c9d60
Show file tree
Hide file tree
Showing 21 changed files with 437 additions and 88 deletions.
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: 'bundler'
directory: '/'
schedule:
interval: 'daily'
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
17 changes: 17 additions & 0 deletions .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Dependabot auto-merge
on: pull_request

permissions:
contents: write
pull-requests: write

jobs:
dependabot:
runs-on: ubuntu-latest
if: ${{ github.actor == 'dependabot[bot]' }}
steps:
- name: Enable auto-merge for Dependabot PRs
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
16 changes: 3 additions & 13 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
name: Ruby
name: Build

on:
push:
branches:
- main

pull_request:
on: push

jobs:
build:
runs-on: ubuntu-latest
name: Ruby ${{ matrix.ruby }}
strategy:
matrix:
ruby:
- '3.3.3'

steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true

- name: Run the default task
run: bundle exec rake
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ GEM
logger
faraday-net_http (3.3.0)
net-http
fiddle (1.1.2)
geocoder (1.8.3)
base64 (>= 0.1.0)
csv (>= 3.0.0)
Expand Down Expand Up @@ -122,6 +123,7 @@ DEPENDENCIES
countries
csv
faraday
fiddle
geocoder
logger
multi_xml
Expand Down
79 changes: 70 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,99 @@
# RateCenter

TODO: Delete this and the text below, and describe your gem
A collection of useful data about [NANPA Rate Centers](https://en.wikipedia.org/wiki/Rate_center).

Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rate_center`. To experiment with that code, run `bin/console` for an interactive prompt.
Data is currently sourced from [Simple Maps](https://simplemaps.com/data/us-cities) and [Local Calling Guide](https://localcallingguide.com/).

## Installation

TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.

Install the gem and add to the application's Gemfile by executing:

```bash
bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
bundle add rate_centers
```

If bundler is not being used to manage dependencies, install the gem by executing:

```bash
gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
gem install rate_centers
```

## Usage

TODO: Write usage instructions here
### Working with Rate Centers

```rb
# Load rate centers
RateCenter.load(:rate_centers, only: { us: [:ny, :ca] }) # Loads rate centers in New York and California
# RateCenter.load(:rate_centers, only: { us: { ny: [ "NWYRCYZN01" ], ca: [ "LSAN DA 01"] } }) # Loads only specific rate centers
# RateCenter.load(:rate_centers, only: { [ :us ] }) # Load all rate centers in US
# RateCenter.load(:rate_centers, :all) # Load all rate centers

# RateCenter::RateCenter.all # returns all rate centers loaded

rate_center = RateCenter::RateCenter.find_by!(country: "US", region: "NY", name: "NWYRCYZN01")
rate_center.full_name # "New York City Zone 01"
rate_center.lata # 132
rate_center.ilec_name # "VERIZON NEW YORK, INC."
rate_center.lat # "40.739362"
rate_center.long # "-73.991043"
rate_center.closest_city.name # "Manhattan"
rate_center.closest_city.distance.value # 5.33
rate_center.closest_city.distance.units # km
```

### Working with Cities

```rb
# Load cities
RateCenter.load(:cities, only: { us: [:ny, :ca] }) # Loads cities in New York and California
# RateCenter.load(:cities, only: { us: { ny: [ "New York" ], ca: [ "Los Angeles"] } }) # Loads only specific cities
# RateCenter.load(:cities, only: { [ :us ] }) # Load all cities in US
# RateCenter.load(:cities, :all) # Load all cities

# RateCenter::City.all # returns all cities loaded

city = RateCenter::City.find_by!(country: "US", region: "NY", name: "New York")
city.lat # "40.6943"
city.log # "-73.9249"
city.nearby_rate_centers.each do |rate_center|
puts "Rate Center: #{rate_center.name}, Distance: #{rate_center.distance.value} #{rate_center.distance.units}"
end
# Rate Center: NWYRCYZN14, Distance: 7.5 km
# Rate Center: NWYRCYZN15, Distance: 7.5 km
# Rate Center: NWYRCYZN11, Distance: 7.5 km
# Rate Center: NWYRCYZN10, Distance: 7.5 km
# Rate Center: NWYRCYZN13, Distance: 7.5 km
# Rate Center: NWYRCYZN09, Distance: 7.5 km
# Rate Center: NWYRCYZN08, Distance: 7.5 km
# Rate Center: NWYRCYZN07, Distance: 7.5 km
# Rate Center: NWYRCYZN06, Distance: 7.5 km
# Rate Center: NWYRCYZN05, Distance: 7.5 km
# Rate Center: NWYRCYZN12, Distance: 7.5 km
# Rate Center: NWYRCYZN04, Distance: 7.5 km
# Rate Center: NWYRCYZN03, Distance: 7.5 km
# Rate Center: NWYRCYZN01, Distance: 7.5 km
# Rate Center: NASSAUZN02, Distance: 18.96 km
# Rate Center: NASSAUZN03, Distance: 20.16 km
```

## Updating Data

In order to pull data from the sources, run the following script

```bash
bin/update_data
```

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
To install this gem onto your local machine, run `bundle exec rake install`.

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rate_center.
Bug reports and pull requests are welcome on GitHub at https://github.com/somleng/rate_center.

## License

Expand Down
4 changes: 2 additions & 2 deletions bin/update_data
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ data_directory = Pathname(File.expand_path("../data/", __dir__))
logger = Logger.new(STDOUT)

logger.info("Fetching city data from SimpleMaps")
# RateCenter::DataSource::SimpleMaps.new.load_data!(data_directory: data_directory.join("cities/us"))
RateCenter::DataSource::SimpleMaps.new.load_data!(data_directory: data_directory.join("cities/us"))
logger.info("Fetching rate center data from LocalCallingGuide")
# RateCenter::DataSource::LocalCallingGuide.new.load_data!(data_directory: data_directory.join("rate_centers/us"))
RateCenter::DataSource::LocalCallingGuide.new.load_data!(data_directory: data_directory.join("rate_centers/us"))
logger.info("Prepping data")
RateCenter::DataPrep.new(data_directory:).call
19 changes: 18 additions & 1 deletion lib/rate_center.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
require "pry"

module RateCenter
class << self
def load(...)
data_loader.load(...)
end

def unload
@data_loader = nil
end

def data_loader
@data_loader ||= DataLoader.new
end
end
end

require_relative "rate_center/version"
require_relative "rate_center/errors"
require_relative "rate_center/data_loader"
require_relative "rate_center/city"
require_relative "rate_center/rate_center"
require_relative "rate_center/version"
33 changes: 33 additions & 0 deletions lib/rate_center/city.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

require "ostruct"
require_relative "collection"
require_relative "vector"
require_relative "distance"

module RateCenter
class City < OpenStruct
extend Collection

class << self
private

def data
::RateCenter.data_loader.cities
end

def load_collection
data.map do |data|
city = new(**data)
city.nearby_rate_centers = Array(data["nearby_rate_centers"]).map do |rate_center|
distance = rate_center.fetch("distance")
Vector.new(
name: rate_center.fetch("name"),
distance: Distance.new(value: distance.fetch("value"), units: distance.fetch("units"))
)
end
city
end
end
end
end
end
23 changes: 23 additions & 0 deletions lib/rate_center/collection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module RateCenter
module Collection
def collection
raise Errors::DataNotLoadedError.new("No data loaded. Load data with RateCenter.load before calling this method") if data.nil?

@collection ||= load_collection
end

def all
collection
end

def find_by(attributes)
collection.find do |region|
attributes.all? { |key, value| region[key] == value }
end
end

def find_by!(*)
find_by(*) || raise(Errors::NotFoundError.new)
end
end
end
84 changes: 36 additions & 48 deletions lib/rate_center/data_loader.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
require "yaml"
require "ostruct"
require "pry"

module RateCenter
class DataLoader
Expand All @@ -22,66 +20,56 @@ def load(type, ...)
else
raise ArgumentError, "Invalid type: #{type}"
end

nil
end

private

def load_data(type, all = nil, **options)
if all
load_data_from(data_directory.join(type).glob("**/*.yml"), type:)
else
load_data_with_filter(options.fetch(:only), type:)
end
end

def load_data_with_filter(filter, type:)
unless filter.is_a?(Hash)
return Array(filter).each_with_object([]) do |country, result|
result.concat(load_country_data(type:, country:))
end
end

filter.each_with_object([]) do |(country, regions), result|
if regions.is_a?(Hash)
regions.each do |region, keys|
data = load_region_data(type:, country:, region:)
result.concat(data.select { |d| Array(keys).include?(d.fetch("name")) })
end
else
Array(regions).each do |region|
result.concat(load_region_data(type:, country:, region:))
end
end
end
end

def load_data_from(files, type:)
Array(files).each_with_object([]) do |file, result|
YAML.load(file.read).fetch(type).each do |data|
result << OpenStruct.new(**data)
end
result.concat(YAML.load(file.read).fetch(type))
end
end

def load_country_data(type:, country:)
load_data_from(data_directory.join(type.to_s, country.to_s.downcase).glob("**/*.yml"), type:)
end

def load_region_data(type:, country:, region:)
load_data_from(
data_directory.join(type.to_s, country.to_s.downcase, "#{region.to_s.downcase}.yml"),
type:
)
end

def load_data(type, all = nil, **options)
directory = data_directory.join(type)

if all
load_data_from(directory.glob("**/*.yml"), type:)
else
filter = options.fetch(:only)

unless filter.is_a?(Hash)
return Array(filter).each_with_object([]) do |country, result|
result.concat(
load_data_from(
directory.join(country.to_s.downcase).glob("**/*.yml"),
type:
)
)
end
end

filter.each_with_object([]) do |(country, regions), result|
if regions.is_a?(Hash)
regions.each do |region, keys|
data = load_region_data(type:, country:, region:)
result.concat(data.select { |d| Array(keys).include?(d.name) })
end
else
Array(regions).each do |region|
result.concat(load_region_data(type:, country:, region:))
end
end
end
end
end
end
end

# data_loader = DataLoader.new
# data_loader.load("all")
# data_loader.load("cities", "all")
# data_loader.load("cities", only: "us")
# data_loader.load("cities", only: { "us" => ["ny"] }, "ca" => ["foo"])
# data_loader.load("rate_centers", "all")
# data_loader.load("rate_centers", "us")
# data_loader.load("rate_centers", only: "us" => { "ny" => ["ny"] })
3 changes: 3 additions & 0 deletions lib/rate_center/distance.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module RateCenter
Distance = Struct.new(:value, :units, keyword_init: true)
end
6 changes: 6 additions & 0 deletions lib/rate_center/errors.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module RateCenter
module Errors
class NotFoundError < StandardError; end
class DataNotLoadedError < StandardError; end
end
end
Loading

0 comments on commit 57c9d60

Please sign in to comment.