Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add tuple schema

Change-Id: Ifa26f01e88473c0f64f4722f07a9a9f81824179e
  • Loading branch information...
commit 91d34d1dec52aa927c3af1acfea0c4c169f37141 1 parent f0f924c
mpage authored
View
3  README.md
@@ -29,6 +29,8 @@ by default. The provided schemas are:
* _Record_ - Accepts hashes with known keys. Each key has a supplied schema,
against which its value must validate.
* _Regexp_ - Accepts strings that match a supplied regular expression.
+* _Tuple_ - Accepts arrays of a given length whose elements validate
+ against their respective schemas.
* _Value_ - Accepts values using ```==```.
## Usage
@@ -66,6 +68,7 @@ be self-explanatory.
"one_or_two" => enum(1, 2),
"strs_to_ints" => dict(String, Integer),
"foo_prefix" => /^foo/,
+ "three_ints" => tuple(Integer, Integer, Integer),
}
end
View
1  lib/membrane/schema.rb
@@ -7,6 +7,7 @@
require "membrane/schema/list"
require "membrane/schema/record"
require "membrane/schema/regexp"
+require "membrane/schema/tuple"
require "membrane/schema/value"
module Membrane
View
48 lib/membrane/schema/tuple.rb
@@ -0,0 +1,48 @@
+require "membrane/errors"
+require "membrane/schema/base"
+
+module Membrane
+ module Schema
+ end
+end
+
+class Membrane::Schema::Tuple < Membrane::Schema::Base
+ attr_reader :elem_schemas
+
+ def initialize(*elem_schemas)
+ @elem_schemas = elem_schemas
+ end
+
+ def validate(object)
+ if !object.kind_of?(Array)
+ emsg = "Expected instance of Array, given instance of #{object.class}"
+ raise Membrane::SchemaValidationError.new(emsg)
+ end
+
+ expected = @elem_schemas.length
+ actual = object.length
+
+ if actual != expected
+ emsg = "Expected #{expected} element(s), given #{actual}"
+ raise Membrane::SchemaValidationError.new(emsg)
+ end
+
+ errors = {}
+
+ @elem_schemas.each_with_index do |schema, ii|
+ begin
+ schema.validate(object[ii])
+ rescue Membrane::SchemaValidationError => e
+ errors[ii] = e
+ end
+ end
+
+ if errors.size > 0
+ emsg = "There were errors at the following indices: " \
+ + errors.map { |ii, err| "#{ii} => #{err}" }.join(", ")
+ raise Membrane::SchemaValidationError.new(emsg)
+ end
+
+ nil
+ end
+end
View
8 lib/membrane/schema_parser.rb
@@ -8,6 +8,7 @@ class Dsl
OptionalKeyMarker = Struct.new(:key)
DictionaryMarker = Struct.new(:key_schema, :value_schema)
EnumMarker = Struct.new(:elem_schemas)
+ TupleMarker = Struct.new(:elem_schemas)
def any
Membrane::Schema::Any.new
@@ -28,6 +29,10 @@ def dict(key_schema, value_schema)
def optional(key)
Dsl::OptionalKeyMarker.new(key)
end
+
+ def tuple(*elem_schemas)
+ TupleMarker.new(elem_schemas)
+ end
end
def self.parse(&blk)
@@ -58,6 +63,9 @@ def do_parse(object)
when Dsl::EnumMarker
elem_schemas = object.elem_schemas.map { |s| do_parse(s) }
Membrane::Schema::Enum.new(*elem_schemas)
+ when Dsl::TupleMarker
+ elem_schemas = object.elem_schemas.map { |s| do_parse(s) }
+ Membrane::Schema::Tuple.new(*elem_schemas)
when Membrane::Schema::Base
object
else
View
14 spec/schema_parser_spec.rb
@@ -47,6 +47,20 @@
schema.value_schema.klass.should == Integer
end
+ it "should translate 'tuple' into Membrane::Schema::Tuple" do
+ schema = parser.parse { tuple(String, any, Integer) }
+
+ schema.class.should == Membrane::Schema::Tuple
+
+ schema.elem_schemas[0].class.should == Membrane::Schema::Class
+ schema.elem_schemas[0].klass.should == String
+
+ schema.elem_schemas[1].class == Membrane::Schema::Any
+
+ schema.elem_schemas[2].class.should == Membrane::Schema::Class
+ schema.elem_schemas[2].klass.should == Integer
+ end
+
it "should translate classes into Membrane::Schema::Class" do
schema = parser.parse { String }
View
29 spec/tuple_schema_spec.rb
@@ -0,0 +1,29 @@
+require "spec_helper"
+
+describe Membrane::Schema::Tuple do
+ let(:schema) do
+ Membrane::Schema::Tuple.new(Membrane::Schema::Class.new(String),
+ Membrane::Schema::ANY,
+ Membrane::Schema::Class.new(Integer))
+ end
+
+ describe "#validate" do
+ it "should raise an error if the validated object isn't an array" do
+ expect_validation_failure(schema, {}, /Array/)
+ end
+
+ it "should raise an error if the validated object has too many/few items" do
+ expect_validation_failure(schema, ["foo", 2], /element/)
+ expect_validation_failure(schema, ["foo", 2, "bar", 3], /element/)
+ end
+
+ it "should raise an error if any of the items do not validate" do
+ expect_validation_failure(schema, [5, 2, 0], /0 =>/)
+ expect_validation_failure(schema, ["foo", 2, "foo"], /2 =>/)
+ end
+
+ it "should return nil when validation succeeds" do
+ schema.validate(["foo", "bar", 5]).should be_nil
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.