From 8fde715efe72e209a5c272ffe33af356c31234d8 Mon Sep 17 00:00:00 2001 From: Vlad Mehakovic Date: Mon, 1 Apr 2019 14:11:52 +1100 Subject: [PATCH 1/9] Implemented RoutificApi::Project with spec from https://routific-platform.readme.io/reference, rafactored getters and setters to RoutificAPI::Jsonable - can delete all tests for RoutificApi::Project --- .byebug_history | 28 +++++++++++++++++ README.md | 4 +++ lib/routific.rb | 3 ++ lib/routific/jsonable.rb | 61 ++++++++++++++++++++++++++++++++++++++ lib/routific/project.rb | 15 ++++++++++ lib/routific/stop.rb | 11 +++++++ routific.gemspec | 2 ++ spec/helper/factory.rb | 15 ++++++++++ spec/helper/spec_helper.rb | 2 ++ spec/project_spec.rb | 58 ++++++++++++++++++++++++++++++++++++ 10 files changed, 199 insertions(+) create mode 100644 .byebug_history create mode 100644 lib/routific/jsonable.rb create mode 100644 lib/routific/project.rb create mode 100644 lib/routific/stop.rb create mode 100644 spec/project_spec.rb diff --git a/.byebug_history b/.byebug_history new file mode 100644 index 0000000..8184f27 --- /dev/null +++ b/.byebug_history @@ -0,0 +1,28 @@ +exit +@date +@name +@id +@stops +@stop +exit +@stops +stops +stopes +stores +exit +@name +name +self name +set_attrs(params) +params +attrs +exit +params +attrs +exit +self.send(attr).map(&:as_json) +self.send(attr).each(&:as_json) +self.send(attr) +exit +send(attr) +attr diff --git a/README.md b/README.md index 2d277ba..559d55c 100644 --- a/README.md +++ b/README.md @@ -177,3 +177,7 @@ It returns a job object with the following attibutes: - `created_at`, `finished_at`: creation and finish times - `input`: the data used for the request - `route`: a route object + +#### `routific.set_project( data )` + +Read the [platform documentation][https://routific-platform.readme.io/reference] for a full list of attributes. diff --git a/lib/routific.rb b/lib/routific.rb index fd9e1e4..b2086db 100644 --- a/lib/routific.rb +++ b/lib/routific.rb @@ -1,3 +1,4 @@ +require_relative './routific/jsonable' require_relative './routific/location' require_relative './routific/visit' require_relative './routific/break' @@ -6,6 +7,8 @@ require_relative './routific/way_point' require_relative './routific/options' require_relative './routific/job' +require_relative './routific/project' +require_relative './routific/stop' require_relative './util' diff --git a/lib/routific/jsonable.rb b/lib/routific/jsonable.rb new file mode 100644 index 0000000..266ee4f --- /dev/null +++ b/lib/routific/jsonable.rb @@ -0,0 +1,61 @@ +module RoutificApi + class Jsonable + def initialize(params) + set_attrs(params) + end + + def as_json + attrs.inject({}) do |json_data, attr| + set_json(json_data, attr) + json_data + end + end + + private + + def set_attrs(params) + attrs.each do |attr| + set_attr(attr, params[attr.to_s]) + end + end + + def set_attr(attr, value) + define_setter(attr, value) + define_reader(attr) + set_variable(attr, value) + end + + def define_setter(attr, value) + self.class.send(:define_method, "#{ attr }=".to_sym) do |value| + instance_variable_set("@" + attr.to_s, value) + end + end + + def define_reader(attr) + self.class.send(:define_method, attr.to_sym) do + instance_variable_get("@" + attr.to_s) + end + end + + def set_variable(attr, value) + self.send("#{ attr }=".to_sym, value) + end + + def set_json(data, attr) + enums.include?(attr) ? set_enum_json(data, attr) : set_value_json(data, attr) + end + + def set_value_json(data, attr) + data[attr.to_s] = add_attr_if_exists(attr) + end + + def set_enum_json(data, attr) + data[attr.to_s] = self.send(attr) + .map(&:as_json) + end + + def add_attr_if_exists(attr) + self.send(attr) if self.send(attr) + end + end +end diff --git a/lib/routific/project.rb b/lib/routific/project.rb new file mode 100644 index 0000000..156e309 --- /dev/null +++ b/lib/routific/project.rb @@ -0,0 +1,15 @@ +module RoutificApi + class Project < Jsonable + def values + %i(id name date) + end + + def enums + %i(drivers stops settings) + end + + def attrs + values + enums + end + end +end diff --git a/lib/routific/stop.rb b/lib/routific/stop.rb new file mode 100644 index 0000000..70a1488 --- /dev/null +++ b/lib/routific/stop.rb @@ -0,0 +1,11 @@ +module RoutificApi + class Stop + def initialize(params) + + end + + def as_json + 'JSON' + end + end +end diff --git a/routific.gemspec b/routific.gemspec index 6ba1655..6202baf 100644 --- a/routific.gemspec +++ b/routific.gemspec @@ -7,6 +7,8 @@ Gem::Specification.new do |s| s.add_development_dependency('rspec', '~> 3.0') s.add_development_dependency('faker', '>= 1.6.2') s.add_development_dependency('dotenv', '~> 0.11') + s.add_development_dependency('rb-readline', '~> 0.5.3') + s.add_development_dependency('byebug', '~> 11.0') s.summary = 'routific API' s.description = 'Gem to use Routific API' s.email = 'support@routific.com' diff --git a/spec/helper/factory.rb b/spec/helper/factory.rb index 59f77b0..012369e 100644 --- a/spec/helper/factory.rb +++ b/spec/helper/factory.rb @@ -65,6 +65,21 @@ class Factory } BREAK = RoutificApi::Break.new(BREAK_PARAMS) + # Factory and constants for stop + STOP_PARAMS = nil + STOP = RoutificApi::Stop.new(STOP_PARAMS) + + # Factory and constants for project + PROJECT_NAME = Faker::Lorem.word + PROJECT_DATE = Date.today.strftime + PROJECT_STOPS = [STOP] + PROJECT_PARAMS = { + "name" => PROJECT_NAME, + "date" => PROJECT_DATE, + "stops" => PROJECT_STOPS + } + PROJECT = RoutificApi::Project.new(PROJECT_PARAMS) + # Factory and constants for vehicle VEHICLE_ID = Faker::Lorem.word VEHICLE_NAME = Faker::Lorem.word diff --git a/spec/helper/spec_helper.rb b/spec/helper/spec_helper.rb index 65b0b39..469b937 100644 --- a/spec/helper/spec_helper.rb +++ b/spec/helper/spec_helper.rb @@ -6,6 +6,8 @@ require 'dotenv' Dotenv.load +require 'byebug' + require 'routific' require_relative './factory' diff --git a/spec/project_spec.rb b/spec/project_spec.rb new file mode 100644 index 0000000..c24e2b9 --- /dev/null +++ b/spec/project_spec.rb @@ -0,0 +1,58 @@ +require_relative './helper/spec_helper' +require_relative '../lib/util' + +describe RoutificApi::Project do + describe "valid parameters" do + subject(:project) { Factory::PROJECT } + + it "has name" do + expect(project.name).to eq(Factory::PROJECT_NAME) + end + + it "has date" do + expect(project.date).to eq(Factory::PROJECT_DATE) + end + + it "has id" do + expect(project.id).to eq(nil) + end + + it "has drivers" + + it "has stops" do + expect(project.stops.class).to eq(Array) + expect(project.stops.first).to eq(Factory::STOP) + end + + it "has settings" + + describe "#as_json" do + subject(:projectJSON) { project.as_json } + + it "can be reconverted to JSON" do + expect { projectJSON }.to_not raise_error + end + + it "has name" do + expect(projectJSON["name"]).to eq(Factory::PROJECT_NAME) + end + + it "has date" do + expect(projectJSON["date"]).to eq(Factory::PROJECT_DATE) + end + + it "has id" do + expect(projectJSON["id"]).to eq(nil) + end + + it "has drivers" + + it "has stops" do + expect(Factory::STOP).to receive(:as_json).and_return("STOP JSON") + expect(projectJSON["stops"].first).to eq("STOP JSON") + end + + it "has settings" + end + end +end From 404d99bd74b8769814f5753ecd6ed638eba3a23d Mon Sep 17 00:00:00 2001 From: Vlad Mehakovic Date: Mon, 1 Apr 2019 14:52:37 +1100 Subject: [PATCH 2/9] Changed RoutificApi::Jsonable to RoutificApi::Attributable ensures attributes are set in sub class and collections are arrays --- .byebug_history | 10 ++++ .gitignore | 3 ++ lib/errors/missing_attribute_error.rb | 5 ++ lib/errors/not_array_error.rb | 5 ++ lib/routific.rb | 4 +- lib/routific/attributable.rb | 76 +++++++++++++++++++++++++++ lib/routific/jsonable.rb | 61 --------------------- lib/routific/project.rb | 4 +- spec/attributable_spec.rb | 43 +++++++++++++++ spec/helper/factory.rb | 37 ++++++++----- spec/project_spec.rb | 58 -------------------- 11 files changed, 171 insertions(+), 135 deletions(-) create mode 100644 lib/errors/missing_attribute_error.rb create mode 100644 lib/errors/not_array_error.rb create mode 100644 lib/routific/attributable.rb delete mode 100644 lib/routific/jsonable.rb create mode 100644 spec/attributable_spec.rb delete mode 100644 spec/project_spec.rb diff --git a/.byebug_history b/.byebug_history index 8184f27..cabfd9b 100644 --- a/.byebug_history +++ b/.byebug_history @@ -1,4 +1,14 @@ exit +self +attr +self.send(attr).class +attr.class +attr +exit +subject +exit +subject +exit @date @name @id diff --git a/.gitignore b/.gitignore index 4b3d9a3..f18f218 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ routific-*.gem # Ignore gem locked versions Gemfile.lock + +# Ignore byebug history +.byebug_history diff --git a/lib/errors/missing_attribute_error.rb b/lib/errors/missing_attribute_error.rb new file mode 100644 index 0000000..9da6a53 --- /dev/null +++ b/lib/errors/missing_attribute_error.rb @@ -0,0 +1,5 @@ +class MissingAttributeError < StandardError + def initialize(msg = "Attribute not set in subclass") + super + end +end diff --git a/lib/errors/not_array_error.rb b/lib/errors/not_array_error.rb new file mode 100644 index 0000000..e198571 --- /dev/null +++ b/lib/errors/not_array_error.rb @@ -0,0 +1,5 @@ +class NotArrayError < StandardError + def initialize(msg = "Not an array") + super + end +end diff --git a/lib/routific.rb b/lib/routific.rb index b2086db..2376358 100644 --- a/lib/routific.rb +++ b/lib/routific.rb @@ -1,4 +1,6 @@ -require_relative './routific/jsonable' +require_relative './errors/not_array_error' +require_relative './errors/missing_attribute_error' +require_relative './routific/attributable' require_relative './routific/location' require_relative './routific/visit' require_relative './routific/break' diff --git a/lib/routific/attributable.rb b/lib/routific/attributable.rb new file mode 100644 index 0000000..d7d3e06 --- /dev/null +++ b/lib/routific/attributable.rb @@ -0,0 +1,76 @@ +module RoutificApi + class Attributable + ATTRS = %i(values collections) + def initialize(params) + ensure_attrs_set + set_attrs(params) + end + + # def as_json + # attrs.inject({}) do |json_data, attr| + # set_json(json_data, attr) + # json_data + # end + # end + + private + + def ensure_attrs_set + ATTRS.each do |attr| + raise MissingAttributeError unless self.respond_to?(attr) + end + end + + def set_attrs(params) + attrs.each do |attr| + set_attr(attr, params[attr.to_s]) + end + end + + def set_attr(attr, value) + ensure_collection_is_array(attr, value) + define_setter(attr, value) + define_reader(attr) + set_variable(attr, value) + end + + def ensure_collection_is_array(attr, value) + if collections.include?(attr) && value.class != Array + raise NotArrayError + end + end + + def define_setter(attr, value) + self.class.send(:define_method, "#{ attr }=".to_sym) do |value| + instance_variable_set("@" + attr.to_s, value) + end + end + + def define_reader(attr) + self.class.send(:define_method, attr.to_sym) do + instance_variable_get("@" + attr.to_s) + end + end + + def set_variable(attr, value) + self.send("#{ attr }=".to_sym, value) + end + + # def set_json(data, attr) + # collections.include?(attr) ? set_collection_json(data, attr) : set_value_json(data, attr) + # end + # + # def set_value_json(data, attr) + # data[attr.to_s] = add_attr_if_exists(attr) + # end + # + # def set_collection_json(data, attr) + # data[attr.to_s] = self.send(attr) + # .map(&:as_json) + # end + + # def add_attr_if_exists(attr) + # self.send(attr) if self.send(attr) + # end + end +end diff --git a/lib/routific/jsonable.rb b/lib/routific/jsonable.rb deleted file mode 100644 index 266ee4f..0000000 --- a/lib/routific/jsonable.rb +++ /dev/null @@ -1,61 +0,0 @@ -module RoutificApi - class Jsonable - def initialize(params) - set_attrs(params) - end - - def as_json - attrs.inject({}) do |json_data, attr| - set_json(json_data, attr) - json_data - end - end - - private - - def set_attrs(params) - attrs.each do |attr| - set_attr(attr, params[attr.to_s]) - end - end - - def set_attr(attr, value) - define_setter(attr, value) - define_reader(attr) - set_variable(attr, value) - end - - def define_setter(attr, value) - self.class.send(:define_method, "#{ attr }=".to_sym) do |value| - instance_variable_set("@" + attr.to_s, value) - end - end - - def define_reader(attr) - self.class.send(:define_method, attr.to_sym) do - instance_variable_get("@" + attr.to_s) - end - end - - def set_variable(attr, value) - self.send("#{ attr }=".to_sym, value) - end - - def set_json(data, attr) - enums.include?(attr) ? set_enum_json(data, attr) : set_value_json(data, attr) - end - - def set_value_json(data, attr) - data[attr.to_s] = add_attr_if_exists(attr) - end - - def set_enum_json(data, attr) - data[attr.to_s] = self.send(attr) - .map(&:as_json) - end - - def add_attr_if_exists(attr) - self.send(attr) if self.send(attr) - end - end -end diff --git a/lib/routific/project.rb b/lib/routific/project.rb index 156e309..4713228 100644 --- a/lib/routific/project.rb +++ b/lib/routific/project.rb @@ -1,10 +1,10 @@ module RoutificApi - class Project < Jsonable + class Project < Attributable def values %i(id name date) end - def enums + def collections %i(drivers stops settings) end diff --git a/spec/attributable_spec.rb b/spec/attributable_spec.rb new file mode 100644 index 0000000..a2b24de --- /dev/null +++ b/spec/attributable_spec.rb @@ -0,0 +1,43 @@ +require_relative './helper/spec_helper' +require_relative '../lib/util' + +describe RoutificApi::Attributable, focus: true do + let(:subject) { AttributableSubclass.new(params) } + let(:params) { Factory::JSONABLE_PARAMS } + + class AttributableSubclass < RoutificApi::Attributable + def values; %i(val_attr); end + def collections; %i(collection_attr); end + def attrs; values + collections; end + end + + describe "instance variables" do + it "has value" do + expect(subject.val_attr).to eq("VALUE") + end + + context "valid collections" do + it "has collections" do + expect(subject.collection_attr.class).to eq(Array) + expect(subject.collection_attr.first).to eq("COLLECTION") + end + end + + context "invalid collections", focus: true do + let(:params) { Factory::JSONABLE_PARAMS_INVALID_COLLECTION } + + it "raises an error" do + expect { subject }.to raise_error(NotArrayError) + end + end + end + + context "attributes not set" do + it "raises a missing attribute error" do + %i(values collections).each do |meth| + AttributableSubclass.class_eval("undef #{ meth }") + expect { subject }.to raise_error(MissingAttributeError) + end + end + end +end diff --git a/spec/helper/factory.rb b/spec/helper/factory.rb index 012369e..1c973b6 100644 --- a/spec/helper/factory.rb +++ b/spec/helper/factory.rb @@ -52,7 +52,7 @@ class Factory VISIT_PARAMS_MULTIPLE_TYPE["type"] = MULTIPLE_TYPE VISIT_MULTIPLE_TYPE = RoutificApi::Visit.new(VISIT_ID, VISIT_PARAMS_MULTIPLE_TYPE) - # Factoru and constants for break + # Factory and constants for break BREAK_ID = Faker::Lorem.word BREAK_START = "12:00" BREAK_END = "12:30" @@ -65,20 +65,31 @@ class Factory } BREAK = RoutificApi::Break.new(BREAK_PARAMS) - # Factory and constants for stop - STOP_PARAMS = nil - STOP = RoutificApi::Stop.new(STOP_PARAMS) + # Constants for jsonable + JSONABLE_PARAMS = { + "val_attr" => "VALUE", + "collection_attr" => ["COLLECTION"] + } - # Factory and constants for project - PROJECT_NAME = Faker::Lorem.word - PROJECT_DATE = Date.today.strftime - PROJECT_STOPS = [STOP] - PROJECT_PARAMS = { - "name" => PROJECT_NAME, - "date" => PROJECT_DATE, - "stops" => PROJECT_STOPS + JSONABLE_PARAMS_INVALID_COLLECTION = { + "val_attr" => "VALUE", + "collection_attr" => "COLLECTION" } - PROJECT = RoutificApi::Project.new(PROJECT_PARAMS) + + # Factory and constants for stop + # STOP_PARAMS = nil + # STOP = RoutificApi::Stop.new(STOP_PARAMS) + # + # # Factory and constants for project + # PROJECT_NAME = Faker::Lorem.word + # PROJECT_DATE = Date.today.strftime + # PROJECT_STOPS = [STOP] + # PROJECT_PARAMS = { + # "name" => PROJECT_NAME, + # "date" => PROJECT_DATE, + # "stops" => PROJECT_STOPS + # } + # PROJECT = RoutificApi::Project.new(PROJECT_PARAMS) # Factory and constants for vehicle VEHICLE_ID = Faker::Lorem.word diff --git a/spec/project_spec.rb b/spec/project_spec.rb deleted file mode 100644 index c24e2b9..0000000 --- a/spec/project_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -require_relative './helper/spec_helper' -require_relative '../lib/util' - -describe RoutificApi::Project do - describe "valid parameters" do - subject(:project) { Factory::PROJECT } - - it "has name" do - expect(project.name).to eq(Factory::PROJECT_NAME) - end - - it "has date" do - expect(project.date).to eq(Factory::PROJECT_DATE) - end - - it "has id" do - expect(project.id).to eq(nil) - end - - it "has drivers" - - it "has stops" do - expect(project.stops.class).to eq(Array) - expect(project.stops.first).to eq(Factory::STOP) - end - - it "has settings" - - describe "#as_json" do - subject(:projectJSON) { project.as_json } - - it "can be reconverted to JSON" do - expect { projectJSON }.to_not raise_error - end - - it "has name" do - expect(projectJSON["name"]).to eq(Factory::PROJECT_NAME) - end - - it "has date" do - expect(projectJSON["date"]).to eq(Factory::PROJECT_DATE) - end - - it "has id" do - expect(projectJSON["id"]).to eq(nil) - end - - it "has drivers" - - it "has stops" do - expect(Factory::STOP).to receive(:as_json).and_return("STOP JSON") - expect(projectJSON["stops"].first).to eq("STOP JSON") - end - - it "has settings" - end - end -end From f1bafc2b5189d4226034c921a53f62fc94be07b5 Mon Sep 17 00:00:00 2001 From: Vlad Mehakovic Date: Mon, 1 Apr 2019 15:24:26 +1100 Subject: [PATCH 3/9] RoutificApi::Jsonable module enables #as_json, converts values to key, value pair and converts collections to an array of the collection's #as_json value --- .byebug_history | 5 +++++ lib/routific.rb | 1 + lib/routific/attributable.rb | 30 ++++++------------------------ lib/routific/jsonable.rb | 29 +++++++++++++++++++++++++++++ lib/routific/project.rb | 4 ---- lib/routific/stop.rb | 8 ++++---- spec/attributable_spec.rb | 10 ++++------ spec/helper/factory.rb | 25 ++++++++----------------- spec/jsonable_spec.rb | 24 ++++++++++++++++++++++++ 9 files changed, 81 insertions(+), 55 deletions(-) create mode 100644 lib/routific/jsonable.rb create mode 100644 spec/jsonable_spec.rb diff --git a/.byebug_history b/.byebug_history index cabfd9b..7c3f42a 100644 --- a/.byebug_history +++ b/.byebug_history @@ -1,4 +1,9 @@ exit +JSON.parse({'blh': 'ljl'}) +JSON.parse({'blh'=> 'ljl'}) +JSON.parse(result) +result +exit self attr self.send(attr).class diff --git a/lib/routific.rb b/lib/routific.rb index 2376358..98cdc4e 100644 --- a/lib/routific.rb +++ b/lib/routific.rb @@ -1,5 +1,6 @@ require_relative './errors/not_array_error' require_relative './errors/missing_attribute_error' +require_relative './routific/jsonable' require_relative './routific/attributable' require_relative './routific/location' require_relative './routific/visit' diff --git a/lib/routific/attributable.rb b/lib/routific/attributable.rb index d7d3e06..5b4eff2 100644 --- a/lib/routific/attributable.rb +++ b/lib/routific/attributable.rb @@ -1,20 +1,19 @@ module RoutificApi class Attributable + include RoutificApi::Jsonable + ATTRS = %i(values collections) def initialize(params) ensure_attrs_set set_attrs(params) end - # def as_json - # attrs.inject({}) do |json_data, attr| - # set_json(json_data, attr) - # json_data - # end - # end - private + def attrs + values + collections + end + def ensure_attrs_set ATTRS.each do |attr| raise MissingAttributeError unless self.respond_to?(attr) @@ -55,22 +54,5 @@ def define_reader(attr) def set_variable(attr, value) self.send("#{ attr }=".to_sym, value) end - - # def set_json(data, attr) - # collections.include?(attr) ? set_collection_json(data, attr) : set_value_json(data, attr) - # end - # - # def set_value_json(data, attr) - # data[attr.to_s] = add_attr_if_exists(attr) - # end - # - # def set_collection_json(data, attr) - # data[attr.to_s] = self.send(attr) - # .map(&:as_json) - # end - - # def add_attr_if_exists(attr) - # self.send(attr) if self.send(attr) - # end end end diff --git a/lib/routific/jsonable.rb b/lib/routific/jsonable.rb new file mode 100644 index 0000000..296cf23 --- /dev/null +++ b/lib/routific/jsonable.rb @@ -0,0 +1,29 @@ +module RoutificApi + module Jsonable + def as_json + attrs.inject({}) do |json_data, attr| + set_json(json_data, attr) + json_data + end + end + + private + + def set_json(data, attr) + collections.include?(attr) ? set_json_collection(data, attr) : set_json_value(data, attr) + end + + def set_json_value(data, attr) + data[attr.to_s] = add_attr_if_exists(attr) + end + + def set_json_collection(data, attr) + data[attr.to_s] = self.send(attr) + .map(&:as_json) + end + + def add_attr_if_exists(attr) + self.send(attr) if self.send(attr) + end + end +end diff --git a/lib/routific/project.rb b/lib/routific/project.rb index 4713228..8a67846 100644 --- a/lib/routific/project.rb +++ b/lib/routific/project.rb @@ -7,9 +7,5 @@ def values def collections %i(drivers stops settings) end - - def attrs - values + enums - end end end diff --git a/lib/routific/stop.rb b/lib/routific/stop.rb index 70a1488..b8d21a0 100644 --- a/lib/routific/stop.rb +++ b/lib/routific/stop.rb @@ -1,11 +1,11 @@ module RoutificApi class Stop - def initialize(params) - + def values + %i(name location start end duration load priority phone_number email notes custom_notes) end - def as_json - 'JSON' + def collections + %i(types) end end end diff --git a/spec/attributable_spec.rb b/spec/attributable_spec.rb index a2b24de..9ca0458 100644 --- a/spec/attributable_spec.rb +++ b/spec/attributable_spec.rb @@ -1,14 +1,12 @@ require_relative './helper/spec_helper' -require_relative '../lib/util' -describe RoutificApi::Attributable, focus: true do +describe RoutificApi::Attributable do let(:subject) { AttributableSubclass.new(params) } - let(:params) { Factory::JSONABLE_PARAMS } + let(:params) { Factory::ATTRIBUTABLE_PARAMS } class AttributableSubclass < RoutificApi::Attributable def values; %i(val_attr); end def collections; %i(collection_attr); end - def attrs; values + collections; end end describe "instance variables" do @@ -23,8 +21,8 @@ def attrs; values + collections; end end end - context "invalid collections", focus: true do - let(:params) { Factory::JSONABLE_PARAMS_INVALID_COLLECTION } + context "invalid collections" do + let(:params) { Factory::ATTRIBUTABLE_PARAMS_INVALID_COLLECTION } it "raises an error" do expect { subject }.to raise_error(NotArrayError) diff --git a/spec/helper/factory.rb b/spec/helper/factory.rb index 1c973b6..efecfa4 100644 --- a/spec/helper/factory.rb +++ b/spec/helper/factory.rb @@ -65,31 +65,22 @@ class Factory } BREAK = RoutificApi::Break.new(BREAK_PARAMS) - # Constants for jsonable - JSONABLE_PARAMS = { + # Constants for attributable + ATTRIBUTABLE_PARAMS = { "val_attr" => "VALUE", "collection_attr" => ["COLLECTION"] } - JSONABLE_PARAMS_INVALID_COLLECTION = { + ATTRIBUTABLE_PARAMS_INVALID_COLLECTION = { "val_attr" => "VALUE", "collection_attr" => "COLLECTION" } - # Factory and constants for stop - # STOP_PARAMS = nil - # STOP = RoutificApi::Stop.new(STOP_PARAMS) - # - # # Factory and constants for project - # PROJECT_NAME = Faker::Lorem.word - # PROJECT_DATE = Date.today.strftime - # PROJECT_STOPS = [STOP] - # PROJECT_PARAMS = { - # "name" => PROJECT_NAME, - # "date" => PROJECT_DATE, - # "stops" => PROJECT_STOPS - # } - # PROJECT = RoutificApi::Project.new(PROJECT_PARAMS) + # Constants for jsonable + JSONABLE_PARAMS = { + "val_attr" => "VALUE", + "collection_attr" => [OpenStruct.new(as_json: "COLLECTION")] + } # Factory and constants for vehicle VEHICLE_ID = Faker::Lorem.word diff --git a/spec/jsonable_spec.rb b/spec/jsonable_spec.rb new file mode 100644 index 0000000..711069e --- /dev/null +++ b/spec/jsonable_spec.rb @@ -0,0 +1,24 @@ +require_relative './helper/spec_helper' + +describe RoutificApi::Jsonable, focus: true do + let(:subject) { JsonableSubclass.new(params) } + let(:params) { Factory::JSONABLE_PARAMS } + + class JsonableSubclass < RoutificApi::Attributable + include RoutificApi::Jsonable + def values; %i(val_attr); end + def collections; %i(collection_attr); end + end + + describe "#as_json" do + let(:result) { subject.as_json } + + it "sets the value" do + expect(result["val_attr"]).to eq("VALUE") + end + + it "sets the collection's as_json value" do + expect(result["collection_attr"].first).to eq("COLLECTION") + end + end +end From cd4d944b2e17c407ccb83145718b325773cba3a3 Mon Sep 17 00:00:00 2001 From: Vlad Mehakovic Date: Mon, 1 Apr 2019 15:46:27 +1100 Subject: [PATCH 4/9] Added project input objects --- lib/routific/attributable.rb | 4 ++-- lib/routific/coords.rb | 15 +++++++++++++++ lib/routific/driver.rb | 15 +++++++++++++++ lib/routific/jsonable.rb | 8 +++++++- lib/routific/lat.rb | 4 ++++ lib/routific/lng.rb | 4 ++++ lib/routific/project.rb | 4 ++++ lib/routific/project_location.rb | 15 +++++++++++++++ lib/routific/settings.rb | 15 +++++++++++++++ lib/routific/simple_attributable.rb | 19 +++++++++++++++++++ lib/routific/stop.rb | 6 +++++- lib/routific/type.rb | 4 ++++ spec/attributable_spec.rb | 3 ++- spec/helper/factory.rb | 3 +++ spec/jsonable_spec.rb | 7 ++++++- 15 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 lib/routific/coords.rb create mode 100644 lib/routific/driver.rb create mode 100644 lib/routific/lat.rb create mode 100644 lib/routific/lng.rb create mode 100644 lib/routific/project_location.rb create mode 100644 lib/routific/settings.rb create mode 100644 lib/routific/simple_attributable.rb create mode 100644 lib/routific/type.rb diff --git a/lib/routific/attributable.rb b/lib/routific/attributable.rb index 5b4eff2..ab388fd 100644 --- a/lib/routific/attributable.rb +++ b/lib/routific/attributable.rb @@ -2,7 +2,7 @@ module RoutificApi class Attributable include RoutificApi::Jsonable - ATTRS = %i(values collections) + ATTRS = %i(values object_values collections) def initialize(params) ensure_attrs_set set_attrs(params) @@ -11,7 +11,7 @@ def initialize(params) private def attrs - values + collections + values + object_values + collections end def ensure_attrs_set diff --git a/lib/routific/coords.rb b/lib/routific/coords.rb new file mode 100644 index 0000000..22ddee2 --- /dev/null +++ b/lib/routific/coords.rb @@ -0,0 +1,15 @@ +module RoutificApi + class Coords < Attributable + def values + [] + end + + def object_values + %(lat lng) + end + + def collections + [] + end + end +end diff --git a/lib/routific/driver.rb b/lib/routific/driver.rb new file mode 100644 index 0000000..73f9e1d --- /dev/null +++ b/lib/routific/driver.rb @@ -0,0 +1,15 @@ +module RoutificApi + class Driver < Attributable + def values + %i(name shift_start shift_end phone_number speed capacity) + end + + def object_values + %i(start_location end_location break) + end + + def collections + %i(types) + end + end +end diff --git a/lib/routific/jsonable.rb b/lib/routific/jsonable.rb index 296cf23..918ead9 100644 --- a/lib/routific/jsonable.rb +++ b/lib/routific/jsonable.rb @@ -10,7 +10,9 @@ def as_json private def set_json(data, attr) - collections.include?(attr) ? set_json_collection(data, attr) : set_json_value(data, attr) + return set_json_collection(data, attr) if collections.include?(attr) + return set_object_value(data, attr) if object_values.include?(attr) + set_json_value(data, attr) end def set_json_value(data, attr) @@ -22,6 +24,10 @@ def set_json_collection(data, attr) .map(&:as_json) end + def set_object_value(data, attr) + data[attr.to_s] = self.send(attr).as_json + end + def add_attr_if_exists(attr) self.send(attr) if self.send(attr) end diff --git a/lib/routific/lat.rb b/lib/routific/lat.rb new file mode 100644 index 0000000..e391b54 --- /dev/null +++ b/lib/routific/lat.rb @@ -0,0 +1,4 @@ +module RoutificApi + class Lat < SimpleAttributable + end +end diff --git a/lib/routific/lng.rb b/lib/routific/lng.rb new file mode 100644 index 0000000..4b35209 --- /dev/null +++ b/lib/routific/lng.rb @@ -0,0 +1,4 @@ +module RoutificApi + class Lng < SimpleAttributable + end +end diff --git a/lib/routific/project.rb b/lib/routific/project.rb index 8a67846..b45f0f0 100644 --- a/lib/routific/project.rb +++ b/lib/routific/project.rb @@ -4,6 +4,10 @@ def values %i(id name date) end + def object_values + [] + end + def collections %i(drivers stops settings) end diff --git a/lib/routific/project_location.rb b/lib/routific/project_location.rb new file mode 100644 index 0000000..5398015 --- /dev/null +++ b/lib/routific/project_location.rb @@ -0,0 +1,15 @@ +module RoutificApi + class ProjectLocation < Attributable + def values + %i(address) + end + + def object_values + %i(coords) + end + + def collections + [] + end + end +end diff --git a/lib/routific/settings.rb b/lib/routific/settings.rb new file mode 100644 index 0000000..b2d7ecf --- /dev/null +++ b/lib/routific/settings.rb @@ -0,0 +1,15 @@ +module RoutificApi + class Settings < Attributable + def values + %i(max_stop_lateness max_driver_overtime shortest_distance traffic strict_start auto_balance default_load default_duration) + end + + def object_values + [] + end + + def collections + [] + end + end +end diff --git a/lib/routific/simple_attributable.rb b/lib/routific/simple_attributable.rb new file mode 100644 index 0000000..7afa32f --- /dev/null +++ b/lib/routific/simple_attributable.rb @@ -0,0 +1,19 @@ +module RoutificApi + class SimpleAttributable < Attributable + def values + %i(name) + end + + def object_values + [] + end + + def collections + [] + end + + def as_json + name + end + end +end diff --git a/lib/routific/stop.rb b/lib/routific/stop.rb index b8d21a0..03ebde3 100644 --- a/lib/routific/stop.rb +++ b/lib/routific/stop.rb @@ -1,7 +1,11 @@ module RoutificApi class Stop def values - %i(name location start end duration load priority phone_number email notes custom_notes) + %i(name start end duration load priority phone_number email notes) + end + + def object_values + %i(location custom_notes) end def collections diff --git a/lib/routific/type.rb b/lib/routific/type.rb new file mode 100644 index 0000000..a693f4c --- /dev/null +++ b/lib/routific/type.rb @@ -0,0 +1,4 @@ +module RoutificApi + class Type < SimpleAttributable + end +end diff --git a/spec/attributable_spec.rb b/spec/attributable_spec.rb index 9ca0458..f2081d9 100644 --- a/spec/attributable_spec.rb +++ b/spec/attributable_spec.rb @@ -6,6 +6,7 @@ class AttributableSubclass < RoutificApi::Attributable def values; %i(val_attr); end + def object_values; %i(obj_val_attr); end def collections; %i(collection_attr); end end @@ -32,7 +33,7 @@ def collections; %i(collection_attr); end context "attributes not set" do it "raises a missing attribute error" do - %i(values collections).each do |meth| + %i(values object_values collections).each do |meth| AttributableSubclass.class_eval("undef #{ meth }") expect { subject }.to raise_error(MissingAttributeError) end diff --git a/spec/helper/factory.rb b/spec/helper/factory.rb index efecfa4..8bf3b27 100644 --- a/spec/helper/factory.rb +++ b/spec/helper/factory.rb @@ -68,17 +68,20 @@ class Factory # Constants for attributable ATTRIBUTABLE_PARAMS = { "val_attr" => "VALUE", + "obj_val_attr" => OpenStruct.new, "collection_attr" => ["COLLECTION"] } ATTRIBUTABLE_PARAMS_INVALID_COLLECTION = { "val_attr" => "VALUE", + "obj_val_attr" => OpenStruct.new, "collection_attr" => "COLLECTION" } # Constants for jsonable JSONABLE_PARAMS = { "val_attr" => "VALUE", + "obj_val_attr" => OpenStruct.new(as_json: "OBJECT VALUE"), "collection_attr" => [OpenStruct.new(as_json: "COLLECTION")] } diff --git a/spec/jsonable_spec.rb b/spec/jsonable_spec.rb index 711069e..a9abb64 100644 --- a/spec/jsonable_spec.rb +++ b/spec/jsonable_spec.rb @@ -1,12 +1,13 @@ require_relative './helper/spec_helper' -describe RoutificApi::Jsonable, focus: true do +describe RoutificApi::Jsonable do let(:subject) { JsonableSubclass.new(params) } let(:params) { Factory::JSONABLE_PARAMS } class JsonableSubclass < RoutificApi::Attributable include RoutificApi::Jsonable def values; %i(val_attr); end + def object_values; %i(obj_val_attr); end def collections; %i(collection_attr); end end @@ -20,5 +21,9 @@ def collections; %i(collection_attr); end it "sets the collection's as_json value" do expect(result["collection_attr"].first).to eq("COLLECTION") end + + it "sets the object value's as_json value" do + expect(result["obj_val_attr"]).to eq("OBJECT VALUE") + end end end From cfeec1399cdbe949d5295d461c11c6aa31805efa Mon Sep 17 00:00:00 2001 From: Vlad Mehakovic Date: Tue, 2 Apr 2019 09:01:06 +1100 Subject: [PATCH 5/9] Added spec to Util, refactored code out of monolith method in order to allow for interaction with the platform URL --- .byebug_history | 36 +++++++++++++++++++++++++++++ lib/routific/job.rb | 2 +- lib/util.rb | 56 ++++++++++++++++++++++++++++++--------------- spec/util_spec.rb | 44 +++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 20 deletions(-) create mode 100644 spec/util_spec.rb diff --git a/.byebug_history b/.byebug_history index 7c3f42a..598c94a 100644 --- a/.byebug_history +++ b/.byebug_history @@ -1,3 +1,39 @@ +e +exit +data.to_json +data +response +exit +job_data +exit +job_data +exit +job.fetch +job +n +data +result['job_id'] +n +c +response +exit +headers(token) +method.downcase.to_sym +nil.to_json +url(endpoint) +RestClient::Request.execute(method: method.downcase.to_sym,url: url(endpoint),data: data.to_json,headers: headers(token)) +data.to_json +data +response +token +endpoint +method +exit +Util.send_request("POST", "vrp", Routific.token, data) +exit +data +exit +data exit JSON.parse({'blh': 'ljl'}) JSON.parse({'blh'=> 'ljl'}) diff --git a/lib/routific/job.rb b/lib/routific/job.rb index 52c978e..7892173 100644 --- a/lib/routific/job.rb +++ b/lib/routific/job.rb @@ -1,5 +1,5 @@ module RoutificApi - # This class represents a job returned by vrp-long + # This class represents a job returned by vrp-long class Job FIELDS = [:status, :created_at, :finished_at] attr_reader *FIELDS diff --git a/lib/util.rb b/lib/util.rb index 6d7ac73..91f5b85 100644 --- a/lib/util.rb +++ b/lib/util.rb @@ -11,30 +11,48 @@ module Util # data: only for POST requests # def self.send_request(method, endpoint, token = nil, data = nil) - url = BASE_URL + endpoint - headers = { - content_type: :json, - accept: :json - } - headers['Authorization'] = token if token begin - # Sends HTTP request to Routific API server - response = nil - if method == 'GET' - response = RestClient.get(url, headers) - elsif method == 'POST' - response = RestClient.post(url, data.to_json, headers) - end - - return JSON.parse(response) + execute_request(method, endpoint, token, data) rescue => e - puts e - errorResponse = JSON.parse e.response.body - puts "Received HTTP #{e.message}: #{errorResponse["error"]}" - nil + error_response(e) end end + private + + def self.execute_request(method, endpoint, token = nil, data = nil) + response = RestClient::Request.execute(request_params(method, endpoint, token, data)) + JSON.parse(response) + end + + def self.request_params(method, endpoint, token, data) + {}.tap do |params| + params[:method] = method.downcase.to_sym + params[:url] = url(endpoint) + params[:payload] = data.to_json unless data == nil + params[:headers] = headers(token) + end + end + + def self.headers(token) + {}.tap do |header| + header[:content_type] = :json + header[:accept] = :json + header['Authorization'] = token if token + end + end + + def self.url(endpoint) + BASE_URL + endpoint + end + + def self.error_response(e) + puts e + errorResponse = JSON.parse e.response.body + puts "Received HTTP #{ e.message }: #{ errorResponse["error"] }" + nil + end + def self.prefix_token(token) (/bearer /.match(token).nil?) ? "bearer #{token}" : token end diff --git a/spec/util_spec.rb b/spec/util_spec.rb new file mode 100644 index 0000000..575a7d3 --- /dev/null +++ b/spec/util_spec.rb @@ -0,0 +1,44 @@ +require_relative './helper/spec_helper' + +RSpec.describe Util do + let(:subject) { Util } + let(:endpoint) { "endpoint" } + let(:url) { "#{ Util::BASE_URL }#{ endpoint }" } + let(:headers) { "HEADERS" } + let(:data) { { key: "RESULT" } } + + before do + expect(subject).to receive(:headers) + .and_return(headers) + end + + describe ".send_request" do + context "GET" do + let(:method) { "GET" } + let(:result) { subject.send_request(method, endpoint ) } + + before do + expect(RestClient::Request).to receive(:execute).with(method: :get, url: url, headers: headers) + .and_return(data.to_json) + end + + it "passes the method to RestClient" do + expect(result['key']).to eq("RESULT") + end + end + + context "POST" do + let(:method) { "POST" } + let(:result) { subject.send_request(method, endpoint, nil, data ) } + + before do + expect(RestClient::Request).to receive(:execute).with(method: :post, url: url, payload: data.to_json, headers: headers) + .and_return(data.to_json) + end + + it "passes the method to RestClient" do + expect(result['key']).to eq("RESULT") + end + end + end +end From 2abd18f50dc7d5153ba523edfcf7853e422c3b77 Mon Sep 17 00:00:00 2001 From: Vlad Mehakovic Date: Tue, 2 Apr 2019 09:15:29 +1100 Subject: [PATCH 6/9] Added product API to Util --- lib/util.rb | 19 +++++++++++-------- spec/util_spec.rb | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/util.rb b/lib/util.rb index 91f5b85..5024b91 100644 --- a/lib/util.rb +++ b/lib/util.rb @@ -2,7 +2,8 @@ require 'json' module Util - BASE_URL = 'https://api.routific.com/v1/' + BASE_URL = 'https://api.routific.com/v1/' + PRODUCT_URL = 'https://product-api.routific.com/v1.0/' ## # method: "GET", "POST" @@ -10,9 +11,10 @@ module Util # token: if nil, raise ArgumentError; if missing "bearer", prefix # data: only for POST requests # - def self.send_request(method, endpoint, token = nil, data = nil) + def self.send_request(method, endpoint, token = nil, data = nil, product = false) begin - execute_request(method, endpoint, token, data) + params = request_params(method, url(endpoint, product), token, data) + execute_request(params) rescue => e error_response(e) end @@ -20,15 +22,15 @@ def self.send_request(method, endpoint, token = nil, data = nil) private - def self.execute_request(method, endpoint, token = nil, data = nil) - response = RestClient::Request.execute(request_params(method, endpoint, token, data)) + def self.execute_request(params) + response = RestClient::Request.execute(params) JSON.parse(response) end - def self.request_params(method, endpoint, token, data) + def self.request_params(method, url, token, data) {}.tap do |params| params[:method] = method.downcase.to_sym - params[:url] = url(endpoint) + params[:url] = url params[:payload] = data.to_json unless data == nil params[:headers] = headers(token) end @@ -42,7 +44,8 @@ def self.headers(token) end end - def self.url(endpoint) + def self.url(endpoint, product) + return PRODUCT_URL + endpoint if product BASE_URL + endpoint end diff --git a/spec/util_spec.rb b/spec/util_spec.rb index 575a7d3..b20c14e 100644 --- a/spec/util_spec.rb +++ b/spec/util_spec.rb @@ -40,5 +40,20 @@ expect(result['key']).to eq("RESULT") end end + + context "product API" do + let(:method) { "POST" } + let(:result) { subject.send_request(method, endpoint, nil, data, true ) } + let(:url) { "#{ Util::PRODUCT_URL }#{ endpoint }" } + + before do + expect(RestClient::Request).to receive(:execute).with(method: :post, url: url, payload: data.to_json, headers: headers) + .and_return(data.to_json) + end + + it "passes the method to RestClient" do + expect(result['key']).to eq("RESULT") + end + end end end From 40453de0ad9a71e0d39d9e78fd5d1f8eecfa2a3b Mon Sep 17 00:00:00 2001 From: Vlad Mehakovic Date: Tue, 2 Apr 2019 10:08:11 +1100 Subject: [PATCH 7/9] RoutificApi::ProjectFactory creates a RoutificApi::Project from an API response --- .byebug_history | 39 +++++++++++++++++++ lib/routific.rb | 6 +++ lib/routific/attributable.rb | 2 +- lib/routific/project.rb | 4 +- lib/routific/project_factory.rb | 18 +++++++++ spec/helper/factory.rb | 67 +++++++++++++++++++++++++++++++++ spec/helper/spec_helper.rb | 2 + spec/project_factory_spec.rb | 14 +++++++ spec/routific_spec.rb | 9 +++++ 9 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 lib/routific/project_factory.rb create mode 100644 spec/project_factory_spec.rb diff --git a/.byebug_history b/.byebug_history index 598c94a..936c600 100644 --- a/.byebug_history +++ b/.byebug_history @@ -1,3 +1,42 @@ +exit +result +c +exit +value.class +value +exit +params[attr] +params +params[attr.to_s] +attr +exit +self.send(attr) +attr +exit +self.send(attr) +value +attr +exit +collections.include?(attr) +attr +c +n +params +self.collections +self.object_values +ATTRS +exit +params + RoutificApi::Project.new(id: params.fetch(:id),name: params.fetch(:name),date: params.fetch(:date)) + 9: ) + 8: date: params.fetch(:date) + 7: name: params.fetch(:name), + 6: id: params.fetch(:id), +RoutificApi::Project.new( +exit +params +exit +result e exit data.to_json diff --git a/lib/routific.rb b/lib/routific.rb index 98cdc4e..94564aa 100644 --- a/lib/routific.rb +++ b/lib/routific.rb @@ -12,6 +12,7 @@ require_relative './routific/job' require_relative './routific/project' require_relative './routific/stop' +require_relative './routific/project_factory' require_relative './util' @@ -71,6 +72,11 @@ def get_route_async RoutificApi::Job.new(result["job_id"], data) end + def set_project(data) + result = Util.send_request("POST", "project", Routific.token, data, true) + RoutificApi::ProjectFactory.new(result).call + end + class << self # Sets the default access token to use def set_token(token) diff --git a/lib/routific/attributable.rb b/lib/routific/attributable.rb index ab388fd..a498ced 100644 --- a/lib/routific/attributable.rb +++ b/lib/routific/attributable.rb @@ -27,10 +27,10 @@ def set_attrs(params) end def set_attr(attr, value) - ensure_collection_is_array(attr, value) define_setter(attr, value) define_reader(attr) set_variable(attr, value) + ensure_collection_is_array(attr, value) end def ensure_collection_is_array(attr, value) diff --git a/lib/routific/project.rb b/lib/routific/project.rb index b45f0f0..f12c285 100644 --- a/lib/routific/project.rb +++ b/lib/routific/project.rb @@ -5,11 +5,11 @@ def values end def object_values - [] + %i(settings) end def collections - %i(drivers stops settings) + %i(drivers stops) end end end diff --git a/lib/routific/project_factory.rb b/lib/routific/project_factory.rb new file mode 100644 index 0000000..1d9fd0e --- /dev/null +++ b/lib/routific/project_factory.rb @@ -0,0 +1,18 @@ +module RoutificApi + class ProjectFactory + attr_reader :params + def initialize(params) + @params = params + end + + def call + RoutificApi::Project.new( + "id" => params.fetch("id"), + "name" => params.fetch("name"), + "date" => params.fetch("date"), + "drivers" => [], + "stops" => [] + ) + end + end +end diff --git a/spec/helper/factory.rb b/spec/helper/factory.rb index 8bf3b27..3d3f9df 100644 --- a/spec/helper/factory.rb +++ b/spec/helper/factory.rb @@ -213,4 +213,71 @@ class Factory "output" => ROUTE_PARAMS_STRING } JOB = RoutificApi::Job.new(JOB_ID, JOB_INPUT) + + # Constants for ProjectFactory + PROJECT_ID = Faker::Lorem.word + PROJECT_NAME = Faker::Lorem.word + DRIVER_NAME = Faker::Lorem.word + PROJECT_DATA = { + "name" => PROJECT_NAME, + "date" => DateTime.now.strftime('%Y-%m-%d'), + "drivers" => [{ + "name" => DRIVER_NAME, + "start_location" => { + "address" => "555 west hastings, vancouver bc, canada", + "coords" => { + "lat" => 49.2847001, + "lng" => -123.1141236 + } + }, + "end_location" => { + "address" => "555 west hastings, vancouver bc, canada", + "coords" => { + "lat" => 49.2847001, + "lng" => -123.1141236 + } + }, + "shift_start" => "09:00", + "shift_end" => "17:00", + "phone_number" => "+16042597686", + "speed" => 1, + "capacity" => 10, + "types" => ["a", "b"], + "break" => { + "start" => "12:00", + "end" => "13:00" + } + }], + "stops" => [{ + "name" => "Jane Doe", + "location" => { + "address" => "2148 Main St, Vancouver, BC V5T 3C5", + "coords" => { + "lat" => 49.2657634, + "lng" => -123.1004459 + } + }, + "start" => "10:00", + "end" => "11:00", + "duration" => 20, + "types" => ["a"], + "load" => 1, + "priority" => true, + "phone_number" => "+16046204589", + "email" => "jane@doe.com", + "notes" => "Press 304 at buzzer.", + "custom_notes" => {} + }], + "settings" => { + "max_stop_lateness" => 320, + "max_driver_overtime" => 320, + "shortest_distance" => true, + "traffic" => 1.4, + "strict_start" => true, + "auto_balance" => true, + "default_load" => 1, + "default_duration" => 10 + } + } + PROJECT_FACTORY_PARAMS = PROJECT_DATA.merge("id" => PROJECT_ID) end diff --git a/spec/helper/spec_helper.rb b/spec/helper/spec_helper.rb index 469b937..e1c60ca 100644 --- a/spec/helper/spec_helper.rb +++ b/spec/helper/spec_helper.rb @@ -8,6 +8,8 @@ require 'byebug' +require 'date' + require 'routific' require_relative './factory' diff --git a/spec/project_factory_spec.rb b/spec/project_factory_spec.rb new file mode 100644 index 0000000..b03924d --- /dev/null +++ b/spec/project_factory_spec.rb @@ -0,0 +1,14 @@ +require_relative './helper/spec_helper' + +RSpec.describe RoutificApi::ProjectFactory, focus: true do + let(:subject) { described_class.new(params) } + let(:params) { Factory::PROJECT_FACTORY_PARAMS } + + describe "#call" do + let(:result) { subject.call } + + it "returns a project" do + expect(result.class).to eq(RoutificApi::Project) + end + end +end diff --git a/spec/routific_spec.rb b/spec/routific_spec.rb index 9633844..72410e1 100644 --- a/spec/routific_spec.rb +++ b/spec/routific_spec.rb @@ -162,6 +162,15 @@ def set_visit_and_vehicle(routific) expect(job.route).to be_instance_of(RoutificApi::Route) end end + + describe "#set_project" do + let(:result) { routific.set_project(data) } + let(:data) { Factory::PROJECT_DATA } + + it "returns a Project instance" do + expect(result).to be_instance_of(RoutificApi::Project) + end + end end describe "class methods" do From 1cf13f7cd5e5b6d3d70f5aa34f416574a789fbab Mon Sep 17 00:00:00 2001 From: Vlad Mehakovic Date: Tue, 2 Apr 2019 14:00:46 +1100 Subject: [PATCH 8/9] ProjectFactory generates Drivers, Stops and Settings via their Factories --- .byebug_history | 14 +++ lib/routific.rb | 8 ++ lib/routific/driver_factory.rb | 25 ++++ lib/routific/factory_helper.rb | 148 +++++++++++++++++++++++ lib/routific/project_factory.rb | 15 ++- lib/routific/project_location_factory.rb | 17 +++ lib/routific/{settings.rb => setting.rb} | 2 +- lib/routific/setting_factory.rb | 22 ++++ lib/routific/stop.rb | 2 +- lib/routific/stop_factory.rb | 27 +++++ lib/util.rb | 4 +- spec/project_factory_spec.rb | 27 ++++- 12 files changed, 300 insertions(+), 11 deletions(-) create mode 100644 lib/routific/driver_factory.rb create mode 100644 lib/routific/factory_helper.rb create mode 100644 lib/routific/project_location_factory.rb rename lib/routific/{settings.rb => setting.rb} (89%) create mode 100644 lib/routific/setting_factory.rb create mode 100644 lib/routific/stop_factory.rb diff --git a/.byebug_history b/.byebug_history index 936c600..2ddfdf4 100644 --- a/.byebug_history +++ b/.byebug_history @@ -1,4 +1,18 @@ exit +params +exit +params +exit +Object.const_get(class_name) +send(class_name.to_sym) +class_name.to_sym +class_name +c +params +exit +params.fetch("drivers") +params.fetch("drivers"0 +exit result c exit diff --git a/lib/routific.rb b/lib/routific.rb index 94564aa..9db52cc 100644 --- a/lib/routific.rb +++ b/lib/routific.rb @@ -11,8 +11,16 @@ require_relative './routific/options' require_relative './routific/job' require_relative './routific/project' +require_relative './routific/driver' require_relative './routific/stop' +require_relative './routific/setting' +require_relative './routific/project_location' +require_relative './routific/factory_helper' require_relative './routific/project_factory' +require_relative './routific/driver_factory' +require_relative './routific/stop_factory' +require_relative './routific/setting_factory' +require_relative './routific/project_location_factory' require_relative './util' diff --git a/lib/routific/driver_factory.rb b/lib/routific/driver_factory.rb new file mode 100644 index 0000000..46ee8c2 --- /dev/null +++ b/lib/routific/driver_factory.rb @@ -0,0 +1,25 @@ +module RoutificApi + class DriverFactory + include FactoryHelper + + attr_reader :params + def initialize(params) + @params = params + end + + def call + Driver.new( + "name" => name, + "start_location" => start_location, + "end_location" => end_location, + "shift_start" => shift_start, + "shift_end" => shift_end, + "phone_number" => phone_number, + "speed" => speed, + "capacity" => capacity, + "types" => types, + "break" => shift_break + ) + end + end +end diff --git a/lib/routific/factory_helper.rb b/lib/routific/factory_helper.rb new file mode 100644 index 0000000..69f00fa --- /dev/null +++ b/lib/routific/factory_helper.rb @@ -0,0 +1,148 @@ +module RoutificApi + module FactoryHelper + def id + params.fetch("id") + end + + def name + params.fetch("name") + end + + def date + params.fetch("date") + end + + def phone_number + params.fetch("phone_number") + end + + def email + params.fetch("email") + end + + def start_time + params.fetch("start") + end + + def end_time + params.fetch("end") + end + + + def shift_start + params.fetch("shift_start") + end + + def shift_end + params.fetch("shift_end") + end + + def duration + params.fetch("duration") + end + + def speed + params.fetch("speed") + end + + def capacity + params.fetch("capacity") + end + + def types + params.fetch("types") + end + + def load + params.fetch("load") + end + + def priority + params.fetch("priority") + end + + def notes + params.fetch("notes") + end + + def custom_notes + params.fetch("custom_notes") + end + + def shift_break + params.fetch("break") + end + + def address + params.fetch("address") + end + + def coords + params.fetch("coords") + end + + def max_stop_lateness + params.fetch("max_stop_lateness") + end + + def max_driver_overtime + params.fetch("max_driver_overtime") + end + + def shortest_distance + params.fetch("shortest_distance") + end + + def traffic + params.fetch("traffic") + end + + def strict_start + params.fetch("strict_start") + end + + def auto_balance + params.fetch("auto_balance") + end + + def default_load + params.fetch("default_load") + end + + def default_duration + params.fetch("default_duration") + end + + def location + location_factory(params.fetch("location")) + end + + def start_location + location_factory(params.fetch("start_location")) + end + + def end_location + location_factory(params.fetch("end_location")) + end + + def location_factory(params) + RoutificApi::ProjectLocationFactory.new(params).call + end + + def settings + RoutificApi::SettingFactory.new(params.fetch("settings")).call + end + + def collection_factory(type) + params.fetch("#{ type }s").map do |params| + Object + .const_get(class_name(type.capitalize)) + .new(params).call + end + end + + def class_name(name) + "RoutificApi::#{ name }Factory" + end + end +end diff --git a/lib/routific/project_factory.rb b/lib/routific/project_factory.rb index 1d9fd0e..9b2d698 100644 --- a/lib/routific/project_factory.rb +++ b/lib/routific/project_factory.rb @@ -1,17 +1,20 @@ module RoutificApi class ProjectFactory + include FactoryHelper + attr_reader :params def initialize(params) @params = params end def call - RoutificApi::Project.new( - "id" => params.fetch("id"), - "name" => params.fetch("name"), - "date" => params.fetch("date"), - "drivers" => [], - "stops" => [] + Project.new( + "id" => id, + "name" => name, + "date" => date, + "drivers" => collection_factory("driver"), + "stops" => collection_factory("stop"), + "settings" => settings ) end end diff --git a/lib/routific/project_location_factory.rb b/lib/routific/project_location_factory.rb new file mode 100644 index 0000000..6e98b1b --- /dev/null +++ b/lib/routific/project_location_factory.rb @@ -0,0 +1,17 @@ +module RoutificApi + class ProjectLocationFactory + include FactoryHelper + + attr_reader :params + def initialize(params) + @params = params + end + + def call + ProjectLocation.new( + "address" => address, + "coords" => coords + ) + end + end +end diff --git a/lib/routific/settings.rb b/lib/routific/setting.rb similarity index 89% rename from lib/routific/settings.rb rename to lib/routific/setting.rb index b2d7ecf..36ee113 100644 --- a/lib/routific/settings.rb +++ b/lib/routific/setting.rb @@ -1,5 +1,5 @@ module RoutificApi - class Settings < Attributable + class Setting < Attributable def values %i(max_stop_lateness max_driver_overtime shortest_distance traffic strict_start auto_balance default_load default_duration) end diff --git a/lib/routific/setting_factory.rb b/lib/routific/setting_factory.rb new file mode 100644 index 0000000..7f62ed7 --- /dev/null +++ b/lib/routific/setting_factory.rb @@ -0,0 +1,22 @@ +module RoutificApi + class SettingFactory + include FactoryHelper + + attr_reader :params + def initialize(params) + @params = params + end + + def call + Setting.new( + "max_stop_lateness" => max_stop_lateness, + "max_driver_overtime" => max_driver_overtime, + "shortest_distance" => shortest_distance, + "traffic" => traffic, + "strict_start" => strict_start, + "auto_balance" => auto_balance, + "default_load" => default_load, "default_duration" => default_duration + ) + end + end +end diff --git a/lib/routific/stop.rb b/lib/routific/stop.rb index 03ebde3..b3aecb8 100644 --- a/lib/routific/stop.rb +++ b/lib/routific/stop.rb @@ -1,5 +1,5 @@ module RoutificApi - class Stop + class Stop < Attributable def values %i(name start end duration load priority phone_number email notes) end diff --git a/lib/routific/stop_factory.rb b/lib/routific/stop_factory.rb new file mode 100644 index 0000000..b27444c --- /dev/null +++ b/lib/routific/stop_factory.rb @@ -0,0 +1,27 @@ +module RoutificApi + class StopFactory + include FactoryHelper + + attr_reader :params + def initialize(params) + @params = params + end + + def call + Stop.new( + "name" => name, + "location" => location, + "start" => start_time, + "end" => end_time, + "duration" => duration, + "types" => types, + "load" => load, + "priority" => priority, + "phone_number" => phone_number, + "email" => email, + "notes" => notes, + "custom_notes" => custom_notes + ) + end + end +end diff --git a/lib/util.rb b/lib/util.rb index 5024b91..8da3596 100644 --- a/lib/util.rb +++ b/lib/util.rb @@ -27,10 +27,10 @@ def self.execute_request(params) JSON.parse(response) end - def self.request_params(method, url, token, data) + def self.request_params(method, url_val, token, data) {}.tap do |params| params[:method] = method.downcase.to_sym - params[:url] = url + params[:url] = url_val params[:payload] = data.to_json unless data == nil params[:headers] = headers(token) end diff --git a/spec/project_factory_spec.rb b/spec/project_factory_spec.rb index b03924d..b1629dc 100644 --- a/spec/project_factory_spec.rb +++ b/spec/project_factory_spec.rb @@ -1,6 +1,6 @@ require_relative './helper/spec_helper' -RSpec.describe RoutificApi::ProjectFactory, focus: true do +RSpec.describe RoutificApi::ProjectFactory do let(:subject) { described_class.new(params) } let(:params) { Factory::PROJECT_FACTORY_PARAMS } @@ -10,5 +10,30 @@ it "returns a project" do expect(result.class).to eq(RoutificApi::Project) end + + describe "#drivers" do + it "is an array of Driver" do + expect(result.drivers.first.class).to eq(RoutificApi::Driver) + end + + describe "locations" do + it "is an instance of ProjectLocation" do + expect(result.drivers.first.start_location.class).to eq(RoutificApi::ProjectLocation) + expect(result.drivers.first.end_location.class).to eq(RoutificApi::ProjectLocation) + end + end + end + + describe "#stops" do + it "is an array of Stop" do + expect(result.stops.first.class).to eq(RoutificApi::Stop) + end + end + + describe "#settings" do + it "is an instance of Setting" do + expect(result.settings.class).to eq(RoutificApi::Setting) + end + end end end From 3deb28d08d0b86408f1a366678f42c31819fe368 Mon Sep 17 00:00:00 2001 From: Vlad Mehakovic Date: Tue, 2 Apr 2019 16:24:21 +1100 Subject: [PATCH 9/9] Updated readme with correct markdown --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 559d55c..6c77052 100644 --- a/README.md +++ b/README.md @@ -180,4 +180,4 @@ It returns a job object with the following attibutes: #### `routific.set_project( data )` -Read the [platform documentation][https://routific-platform.readme.io/reference] for a full list of attributes. +Read the [platform documentation](https://routific-platform.readme.io/reference) for a full list of attributes.