Skip to content

Commit 9231f80

Browse files
author
Alexandru Popescu
committed
Add initial configuration and CoffeeShop model
1 parent b6d4ba9 commit 9231f80

File tree

8 files changed

+137
-0
lines changed

8 files changed

+137
-0
lines changed

Gemfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,8 @@ end
2020

2121
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
2222
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
23+
24+
gem 'csv'
25+
gem 'httparty'
26+
gem 'pry'
27+
gem 'sinatra'

Gemfile.lock

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,44 @@ GEM
22
remote: https://rubygems.org/
33
specs:
44
ast (2.4.2)
5+
base64 (0.2.0)
6+
bigdecimal (3.1.9)
57
byebug (11.1.3)
8+
coderay (1.1.3)
9+
csv (3.3.2)
610
diff-lcs (1.5.1)
11+
httparty (0.22.0)
12+
csv
13+
mini_mime (>= 1.0.0)
14+
multi_xml (>= 0.5.2)
715
json (2.9.1)
816
language_server-protocol (3.17.0.3)
17+
logger (1.6.5)
18+
method_source (1.1.0)
19+
mini_mime (1.1.5)
20+
multi_xml (0.7.1)
21+
bigdecimal (~> 3.1)
22+
mustermann (3.0.3)
23+
ruby2_keywords (~> 0.0.1)
924
nio4r (2.7.4)
1025
parallel (1.26.3)
1126
parser (3.3.7.0)
1227
ast (~> 2.4.1)
1328
racc
29+
pry (0.15.2)
30+
coderay (~> 1.1)
31+
method_source (~> 1.0)
1432
puma (6.5.0)
1533
nio4r (~> 2.0)
1634
racc (1.8.1)
35+
rack (3.1.8)
36+
rack-protection (4.1.1)
37+
base64 (>= 0.1.0)
38+
logger (>= 1.6.0)
39+
rack (>= 3.0.0, < 4)
40+
rack-session (2.1.0)
41+
base64 (>= 0.1.0)
42+
rack (>= 3.0.0)
1743
rainbow (3.1.1)
1844
regexp_parser (2.10.0)
1945
rspec (3.13.0)
@@ -42,6 +68,15 @@ GEM
4268
rubocop-ast (1.37.0)
4369
parser (>= 3.3.1.0)
4470
ruby-progressbar (1.13.0)
71+
ruby2_keywords (0.0.5)
72+
sinatra (4.1.1)
73+
logger (>= 1.6.0)
74+
mustermann (~> 3.0)
75+
rack (>= 3.0.0, < 4)
76+
rack-protection (= 4.1.1)
77+
rack-session (>= 2.0.0, < 3)
78+
tilt (~> 2.0)
79+
tilt (2.6.0)
4580
unicode-display_width (3.1.4)
4681
unicode-emoji (~> 4.0, >= 4.0.4)
4782
unicode-emoji (4.0.4)
@@ -52,9 +87,13 @@ PLATFORMS
5287

5388
DEPENDENCIES
5489
byebug
90+
csv
91+
httparty
92+
pry
5593
puma (~> 6.5)
5694
rspec (~> 3.10)
5795
rubocop
96+
sinatra
5897
tzinfo-data
5998

6099
RUBY VERSION

app.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# frozen_string_literal: true
2+
3+
# app.rb
4+
require_relative 'config/environment'
5+
6+
# Mount the controller
7+
map '/api' do
8+
run CoffeeShopController
9+
end

app/models/coffee_shop.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# frozen_string_literal: true
2+
3+
class CoffeeShop
4+
class InvalidCoordinatesError < StandardError; end
5+
6+
attr_reader :name, :latitude, :longitude
7+
8+
def initialize(name, latitude, longitude)
9+
@name = validate_name(name)
10+
@latitude = validate_coordinate(latitude.to_f, -90..90, 'Latitude')
11+
@longitude = validate_coordinate(longitude.to_f, -180..180, 'Longitude')
12+
end
13+
14+
def distance_to(user_lat, user_lon)
15+
user_lat = validate_coordinate(user_lat.to_f, -90..90, 'User Latitude')
16+
user_lon = validate_coordinate(user_lon.to_f, -180..180, 'User Longitude')
17+
18+
Math.sqrt(((user_lat - latitude)**2) + ((user_lon - longitude)**2)).round(4)
19+
end
20+
21+
private
22+
23+
def validate_name(name)
24+
name = name.to_s.strip
25+
raise ArgumentError, 'Name cannot be empty' if name.empty?
26+
27+
name
28+
end
29+
30+
def validate_coordinate(coord, range, name)
31+
raise InvalidCoordinatesError, "#{name} must be a number" unless coord.is_a?(Numeric)
32+
raise InvalidCoordinatesError, "#{name} out of range" unless range.include?(coord)
33+
34+
coord
35+
end
36+
end

config/environment.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# frozen_string_literal: true
2+
3+
require 'yaml'
4+
require 'logger'
5+
6+
APP_CONFIG = YAML.load_file(File.join(__dir__, 'settings.yml')).transform_keys(&:to_sym)
7+
APP_LOGGER = Logger.new($stdout)
8+
9+
Dir[File.join(__dir__, '../app/**/*.rb')].each { |file| require file }

config/settings.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
csv_url: 'https://raw.githubusercontent.com/Agilefreaks/test_oop/master/coffee_shops.csv'

spec/models/coffee_shop_spec.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../../app/models/coffee_shop'
4+
5+
RSpec.describe CoffeeShop do
6+
describe '#initialize' do
7+
it 'creates a valid coffee shop' do
8+
shop = CoffeeShop.new('Test Shop', 45.0, -122.0)
9+
10+
expect(shop.name).to eq('Test Shop')
11+
expect(shop.latitude).to eq(45.0)
12+
expect(shop.longitude).to eq(-122.0)
13+
end
14+
15+
it 'raises error for invalid coordinates' do
16+
expect { CoffeeShop.new('Test', 100.0, 0) }.to raise_error(CoffeeShop::InvalidCoordinatesError)
17+
expect { CoffeeShop.new('Test', 0, 200.0) }.to raise_error(CoffeeShop::InvalidCoordinatesError)
18+
end
19+
20+
it 'raises error for empty name' do
21+
expect { CoffeeShop.new('', 0, 0) }.to raise_error(ArgumentError)
22+
end
23+
end
24+
25+
describe '#distance_to' do
26+
let(:shop) { CoffeeShop.new('Test', 0.0, 0.0) }
27+
28+
it 'calculates distance correctly' do
29+
expect(shop.distance_to(3.0, 4.0)).to eq(5.0)
30+
expect(shop.distance_to(1.0, 1.0)).to eq(1.4142)
31+
end
32+
33+
it 'raises error for invalid user coordinates' do
34+
expect { shop.distance_to(95.0, 0) }.to raise_error(CoffeeShop::InvalidCoordinatesError)
35+
end
36+
end
37+
end

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
1818

1919
require 'byebug'
20+
require 'pry'
2021

2122
RSpec.configure do |config|
2223
# rspec-expectations config goes here. You can use an alternate

0 commit comments

Comments
 (0)