From 84649059786a09a0df19460bd33b3dcc713c7409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 15:50:17 +0100 Subject: [PATCH 01/13] Add RangeParser with attributes --- lib/pliny/range_parser.rb | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 lib/pliny/range_parser.rb diff --git a/lib/pliny/range_parser.rb b/lib/pliny/range_parser.rb new file mode 100644 index 00000000..f4f54015 --- /dev/null +++ b/lib/pliny/range_parser.rb @@ -0,0 +1,25 @@ +module Pliny + class RangeParser + attr_reader :range_header + attr_reader :start, :end, :parameters + + def initialize(range_header) + @range_header = range_header + + set_defaults + parse + end + + private + + def parse + + end + + def set_defaults + @start = nil + @end = nil + @parameters = {} + end + end +end From b967f70496493f3f2b71f81dc73a244251ee7860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 15:50:41 +0100 Subject: [PATCH 02/13] Add test with expected range parser behavior --- spec/range_parser_spec.rb | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 spec/range_parser_spec.rb diff --git a/spec/range_parser_spec.rb b/spec/range_parser_spec.rb new file mode 100644 index 00000000..3a70f107 --- /dev/null +++ b/spec/range_parser_spec.rb @@ -0,0 +1,31 @@ +require "spec_helper" + +describe Pliny::RangeParser do + subject(:parser) { described_class.new(range_header) } + + context 'with a bound range' do + let(:range_header) { 'objects 0-99' } + + it 'parses a start and an end' do + assert_equal 0, parser.start + assert_equal 99, parser.end + end + end + + context 'with an unbound range' do + let(:range_header) { 'objects 0-' } + + it 'parses a start' do + assert_equal 0, parser.start + assert_nil parser.end + end + end + + context 'with parameters' do + let(:range_header) { 'objects 0-99; a=b, c=d' } + + it 'parses parameters' do + assert_equal({ a: 'b', c: 'd' }, parser.parameters) + end + end +end From 99610c17e28489b658dbf6140a342d95575784d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 15:51:09 +0100 Subject: [PATCH 03/13] Include RangeParser in Pliny --- lib/pliny.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pliny.rb b/lib/pliny.rb index 9ee4652c..6fd6d11c 100644 --- a/lib/pliny.rb +++ b/lib/pliny.rb @@ -6,6 +6,7 @@ require_relative "pliny/helpers/encode" require_relative "pliny/helpers/params" require_relative "pliny/log" +require_relative "pliny/range_parser" require_relative "pliny/request_store" require_relative "pliny/router" require_relative "pliny/utils" From 774c81d48859967a21a930dedd0ad1a87dee5f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 15:53:37 +0100 Subject: [PATCH 04/13] Handle empty range header --- lib/pliny/range_parser.rb | 1 + spec/range_parser_spec.rb | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/pliny/range_parser.rb b/lib/pliny/range_parser.rb index f4f54015..69e0a186 100644 --- a/lib/pliny/range_parser.rb +++ b/lib/pliny/range_parser.rb @@ -7,6 +7,7 @@ def initialize(range_header) @range_header = range_header set_defaults + return if range_header.nil? parse end diff --git a/spec/range_parser_spec.rb b/spec/range_parser_spec.rb index 3a70f107..a550817e 100644 --- a/spec/range_parser_spec.rb +++ b/spec/range_parser_spec.rb @@ -3,6 +3,16 @@ describe Pliny::RangeParser do subject(:parser) { described_class.new(range_header) } + context 'with an empty header' do + let(:range_header) { nil } + + it 'parses' do + assert_nil parser.start + assert_nil parser.end + assert_equal({}, parser.parameters) + end + end + context 'with a bound range' do let(:range_header) { 'objects 0-99' } From 4b898297faedcfe5165ca42e70ea66fc9b57fd99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 16:01:02 +0100 Subject: [PATCH 05/13] Raise on multiple semicolons --- lib/pliny/range_parser.rb | 7 +++++++ spec/range_parser_spec.rb | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/pliny/range_parser.rb b/lib/pliny/range_parser.rb index 69e0a186..b0e9c5f5 100644 --- a/lib/pliny/range_parser.rb +++ b/lib/pliny/range_parser.rb @@ -3,6 +3,8 @@ class RangeParser attr_reader :range_header attr_reader :start, :end, :parameters + RANGE_FORMAT_ERROR = 'Invalid `Range` header. Please use format like `objects 0-99; sort=name, order=desc`.'.freeze + def initialize(range_header) @range_header = range_header @@ -14,7 +16,12 @@ def initialize(range_header) private def parse + parts = range_header.split(';') + raise_range_format_error if parts.size > 2 + end + def raise_range_format_error + raise Pliny::Errors::BadRequest, RANGE_FORMAT_ERROR end def set_defaults diff --git a/spec/range_parser_spec.rb b/spec/range_parser_spec.rb index a550817e..2a6ede16 100644 --- a/spec/range_parser_spec.rb +++ b/spec/range_parser_spec.rb @@ -38,4 +38,15 @@ assert_equal({ a: 'b', c: 'd' }, parser.parameters) end end + + context 'with multiple semicolons' do + let(:range_header) { 'objects 0-99; a=b; c=d' } + let(:message) { Pliny::RangeParser::RANGE_FORMAT_ERROR } + + it 'raises a bad request' do + assert_raises Pliny::Errors::BadRequest, message do + parser + end + end + end end From 968fb2a38bb1c536943cca07b94566303e9170ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 16:04:09 +0100 Subject: [PATCH 06/13] Add methods to parse bounds and parameters --- lib/pliny/range_parser.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/pliny/range_parser.rb b/lib/pliny/range_parser.rb index b0e9c5f5..616a6e4d 100644 --- a/lib/pliny/range_parser.rb +++ b/lib/pliny/range_parser.rb @@ -18,6 +18,17 @@ def initialize(range_header) def parse parts = range_header.split(';') raise_range_format_error if parts.size > 2 + bounds_str, parameters_str = parts + parse_range_bounds(bounds_str) + parse_range_parameters(parameters_str) + end + + def parse_range_bounds(bounds_str) + + end + + def parse_range_parameters(parameters_str) + end def raise_range_format_error From da27407b5e7408f34a24427b75914e2e078cc244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 16:14:34 +0100 Subject: [PATCH 07/13] Raise on non "objects" unit --- lib/pliny/range_parser.rb | 4 +++- spec/range_parser_spec.rb | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/pliny/range_parser.rb b/lib/pliny/range_parser.rb index 616a6e4d..4f3becc3 100644 --- a/lib/pliny/range_parser.rb +++ b/lib/pliny/range_parser.rb @@ -24,7 +24,9 @@ def parse end def parse_range_bounds(bounds_str) - + return if bounds_str.nil? + unit, bounds = bounds_str.split(%r{\s+}, 2) + raise_range_format_error unless unit.downcase == 'objects' end def parse_range_parameters(parameters_str) diff --git a/spec/range_parser_spec.rb b/spec/range_parser_spec.rb index 2a6ede16..beca6813 100644 --- a/spec/range_parser_spec.rb +++ b/spec/range_parser_spec.rb @@ -49,4 +49,15 @@ end end end + + context 'with a non objects unit' do + let(:range_header) { 'ids 0-99' } + let(:message) { Pliny::RangeParser::RANGE_FORMAT_ERROR } + + it 'raises a bad request' do + assert_raises Pliny::Errors::BadRequest, message do + parser + end + end + end end From 7cebe3c415ee765240d162b34fa302a8ed8b22c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 16:24:02 +0100 Subject: [PATCH 08/13] Parse start and end bounds --- lib/pliny/range_parser.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pliny/range_parser.rb b/lib/pliny/range_parser.rb index 4f3becc3..e71a9c15 100644 --- a/lib/pliny/range_parser.rb +++ b/lib/pliny/range_parser.rb @@ -27,6 +27,10 @@ def parse_range_bounds(bounds_str) return if bounds_str.nil? unit, bounds = bounds_str.split(%r{\s+}, 2) raise_range_format_error unless unit.downcase == 'objects' + if bounds =~ %r{(\d*)-(\d*)} + @start = $1.to_i unless $1.empty? + @end = $2.to_i unless $2.empty? + end end def parse_range_parameters(parameters_str) From 9499700fb7401e1a0811464f1372f3898df5e1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 16:36:00 +0100 Subject: [PATCH 09/13] Parse range parameters --- lib/pliny/range_parser.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pliny/range_parser.rb b/lib/pliny/range_parser.rb index e71a9c15..720b7985 100644 --- a/lib/pliny/range_parser.rb +++ b/lib/pliny/range_parser.rb @@ -34,7 +34,13 @@ def parse_range_bounds(bounds_str) end def parse_range_parameters(parameters_str) - + return if parameters_str.nil? + @parameters = Hash[ + parameters_str.split(',') + .map { |option| option.split('=') } + .select { |k, v| k && v } + .map { |k, v| [k.strip.to_sym, v.strip] } + ] end def raise_range_format_error From cfbca69509afbcfbe19c0a2ed33be55aacb72f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 16:36:59 +0100 Subject: [PATCH 10/13] Check for empty parameters when absent --- spec/range_parser_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/range_parser_spec.rb b/spec/range_parser_spec.rb index beca6813..9feddb30 100644 --- a/spec/range_parser_spec.rb +++ b/spec/range_parser_spec.rb @@ -19,6 +19,7 @@ it 'parses a start and an end' do assert_equal 0, parser.start assert_equal 99, parser.end + assert_equal({}, parser.parameters) end end @@ -28,6 +29,7 @@ it 'parses a start' do assert_equal 0, parser.start assert_nil parser.end + assert_equal({}, parser.parameters) end end From 783b64989b48728cc9c2001d991a0f5308d48dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 16:39:21 +0100 Subject: [PATCH 11/13] styling --- lib/pliny/range_parser.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pliny/range_parser.rb b/lib/pliny/range_parser.rb index 720b7985..a4828aa7 100644 --- a/lib/pliny/range_parser.rb +++ b/lib/pliny/range_parser.rb @@ -25,9 +25,9 @@ def parse def parse_range_bounds(bounds_str) return if bounds_str.nil? - unit, bounds = bounds_str.split(%r{\s+}, 2) + unit, bounds = bounds_str.split(/\s+/, 2) raise_range_format_error unless unit.downcase == 'objects' - if bounds =~ %r{(\d*)-(\d*)} + if bounds =~ /(\d*)-(\d*)/ @start = $1.to_i unless $1.empty? @end = $2.to_i unless $2.empty? end @@ -44,7 +44,7 @@ def parse_range_parameters(parameters_str) end def raise_range_format_error - raise Pliny::Errors::BadRequest, RANGE_FORMAT_ERROR + fail Pliny::Errors::BadRequest, RANGE_FORMAT_ERROR end def set_defaults From a252ca4da536e17968a53eca885425e67470c926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 16:44:56 +0100 Subject: [PATCH 12/13] Clean up start and end bound parsing --- lib/pliny/range_parser.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/pliny/range_parser.rb b/lib/pliny/range_parser.rb index a4828aa7..da4f7c4c 100644 --- a/lib/pliny/range_parser.rb +++ b/lib/pliny/range_parser.rb @@ -27,10 +27,9 @@ def parse_range_bounds(bounds_str) return if bounds_str.nil? unit, bounds = bounds_str.split(/\s+/, 2) raise_range_format_error unless unit.downcase == 'objects' - if bounds =~ /(\d*)-(\d*)/ - @start = $1.to_i unless $1.empty? - @end = $2.to_i unless $2.empty? - end + /(?\d*)-(?\d*)/ =~ bounds + @start = start_bound.to_i unless start_bound.empty? + @end = end_bound.to_i unless end_bound.empty? end def parse_range_parameters(parameters_str) From b8aeda6d5a6e7df9c6e8530463fd966efec7924b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gu=C3=B0mundur=20Bjarni=20=C3=93lafsson?= Date: Sat, 12 Dec 2015 16:46:46 +0100 Subject: [PATCH 13/13] Assert against unbound start bound --- spec/range_parser_spec.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/spec/range_parser_spec.rb b/spec/range_parser_spec.rb index 9feddb30..d606b12e 100644 --- a/spec/range_parser_spec.rb +++ b/spec/range_parser_spec.rb @@ -23,7 +23,17 @@ end end - context 'with an unbound range' do + context 'with an unbound start range' do + let(:range_header) { 'objects -99' } + + it 'parses a start' do + assert_nil parser.start + assert_equal 99, parser.end + assert_equal({}, parser.parameters) + end + end + + context 'with an unbound end range' do let(:range_header) { 'objects 0-' } it 'parses a start' do