diff --git a/lib/mutations.rb b/lib/mutations.rb index cae4ef0..cb33e05 100644 --- a/lib/mutations.rb +++ b/lib/mutations.rb @@ -20,6 +20,7 @@ require 'mutations/model_filter' require 'mutations/array_filter' require 'mutations/hash_filter' +require 'mutations/uri_filter' require 'mutations/outcome' require 'mutations/command' diff --git a/lib/mutations/uri_filter.rb b/lib/mutations/uri_filter.rb new file mode 100644 index 0000000..0247de4 --- /dev/null +++ b/lib/mutations/uri_filter.rb @@ -0,0 +1,45 @@ +require 'uri' + +module Mutations + class UriFilter < AdditionalFilter + @default_options = { + :nils => false, # true allows an explicit nil to be valid. Overrides any other options + :scheme => nil, # restrict the URI to a specific scheme, i.e. 'https' + } + + def filter(data) + if data.nil? + return [nil, nil] if options[:nils] + return [nil, :nils] + end + + case data + when URI # we're good! + when String then + return [nil, :blank] if blank?(data) + begin + data = URI.parse(data) + rescue StandardError => e + return [nil, e.message] + end + else return [nil, :invalid] + end + + if !options[:scheme].nil? + return [nil, :scheme] if blank?(data.scheme) + return [nil, :scheme] if data.scheme.to_sym != options[:scheme] + end + + [data, nil] + end + + private + + def blank?(value) + return true if value.nil? + value = value.strip if value.is_a?(String) + return value.empty? if value.respond_to?(:empty?) + return false + end + end +end diff --git a/spec/uri_filter_spec.rb b/spec/uri_filter_spec.rb new file mode 100644 index 0000000..0c05ed1 --- /dev/null +++ b/spec/uri_filter_spec.rb @@ -0,0 +1,153 @@ +require 'spec_helper' + +describe Mutations::UriFilter do + let(:options){ {} } + let(:outcome){ Mutations::UriFilter.new(options).filter(input) } + let(:result){ outcome[0] } + let(:errors){ outcome[1] } + + describe "#blank" do + subject{ Mutations::UriFilter.new.send(:blank?, value) } + + describe "nil" do + let(:value){ nil } + it{ assert(subject) } + end + + describe "empty string" do + let(:value){ "" } + it{ assert(subject) } + end + + describe "whitespace" do + let(:value){ " " } + it{ assert(subject) } + end + + describe "some text" do + let(:value){ "abc" } + it{ assert(!subject) } + end + end + + describe 'invalid type input' do + let(:input){ true } + + it{ assert_nil(result) } + it{ assert_equal(errors, :invalid) } + end + + describe 'string input' do + let(:input){ 'http://www.altavista.com' } + + describe 'is blank' do + let(:input){ '' } + + it{ assert_nil(result) } + it{ assert_equal(errors, :blank) } + end + + describe 'invalid uri' do + let(:input){ 'oops' } + + it "returns the error" do + URI.stub :parse, lambda {|x| raise 'invalid URI'} do + assert_nil(result) + assert_equal(errors, 'invalid URI') + end + end + end + + describe 'with scheme constraint' do + + describe 'matching constraint' do + let(:options){ { scheme: :http } } + + it{ assert_equal(result, URI.parse(input)) } + it{ assert_nil(errors) } + end + + describe 'not matching constraint' do + let(:options){ { scheme: :https} } + + it{ assert_nil(result) } + it{ assert_equal(errors, :scheme) } + end + + describe 'and blank url scheme' do + let(:options){ { scheme: :http} } + let(:input){ 'altavista.com' } + + it{ assert_nil(result) } + it{ assert_equal(errors, :scheme) } + end + end + + describe 'without scheme constraint' do + describe 'and blank url scheme' do + let(:input){ 'altavista.com' } + + it{ assert_equal(result, URI.parse(input)) } + it{ assert_nil(errors) } + end + end + + end + + describe 'uri input' do + let(:input){ URI.parse('http://www.altavista.com') } + + describe 'with scheme constraint' do + describe 'matching constraint' do + let(:options){ { scheme: :http } } + + it{ assert_equal(result, input) } + it{ assert_nil(errors) } + end + + describe 'not matching constraint' do + let(:options){ { scheme: :https} } + + it{ assert_nil(result) } + it{ assert_equal(errors, :scheme) } + end + + describe 'and blank url scheme' do + let(:options){ { scheme: :http} } + let(:input){ URI.parse('altavista.com') } + + it{ assert_nil(result) } + it{ assert_equal(errors, :scheme) } + end + end + + describe 'without scheme constraint' do + describe 'and blank url scheme' do + let(:input){ URI.parse('altavista.com') } + + it{ assert_equal(result, input) } + it{ assert_nil(errors) } + end + end + + end + + describe 'nil input' do + let(:input){ nil } + + describe 'nils allowed' do + let(:options){ { nils: true } } + + it{ assert_nil(result) } + it{ assert_nil(errors) } + end + + describe 'nils not allowed' do + let(:options){ { nils: false } } + + it{ assert_nil(result) } + it{ assert_equal(errors, :nils) } + end + + end +end