qrb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +58 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +11 -0
- data/README.md +118 -0
- data/Rakefile +11 -0
- data/lib/qrb/Q/default.q +29 -0
- data/lib/qrb/data_type.rb +23 -0
- data/lib/qrb/errors.rb +23 -0
- data/lib/qrb/support/attribute.rb +53 -0
- data/lib/qrb/support/collection_type.rb +25 -0
- data/lib/qrb/support/dress_helper.rb +68 -0
- data/lib/qrb/support/heading.rb +57 -0
- data/lib/qrb/support/type_factory.rb +178 -0
- data/lib/qrb/support.rb +5 -0
- data/lib/qrb/syntax/ad_type.rb +25 -0
- data/lib/qrb/syntax/attribute.rb +11 -0
- data/lib/qrb/syntax/builtin_type.rb +13 -0
- data/lib/qrb/syntax/constraint_def.rb +11 -0
- data/lib/qrb/syntax/constraints.rb +18 -0
- data/lib/qrb/syntax/contract.rb +25 -0
- data/lib/qrb/syntax/definitions.rb +14 -0
- data/lib/qrb/syntax/expression.rb +12 -0
- data/lib/qrb/syntax/heading.rb +15 -0
- data/lib/qrb/syntax/lambda_expr.rb +11 -0
- data/lib/qrb/syntax/named_constraint.rb +11 -0
- data/lib/qrb/syntax/q.citrus +195 -0
- data/lib/qrb/syntax/relation_type.rb +11 -0
- data/lib/qrb/syntax/seq_type.rb +12 -0
- data/lib/qrb/syntax/set_type.rb +12 -0
- data/lib/qrb/syntax/sub_type.rb +13 -0
- data/lib/qrb/syntax/support.rb +13 -0
- data/lib/qrb/syntax/system.rb +15 -0
- data/lib/qrb/syntax/tuple_type.rb +11 -0
- data/lib/qrb/syntax/type_def.rb +14 -0
- data/lib/qrb/syntax/type_ref.rb +13 -0
- data/lib/qrb/syntax/union_type.rb +12 -0
- data/lib/qrb/syntax/unnamed_constraint.rb +11 -0
- data/lib/qrb/syntax.rb +42 -0
- data/lib/qrb/system.rb +63 -0
- data/lib/qrb/type/ad_type.rb +111 -0
- data/lib/qrb/type/builtin_type.rb +56 -0
- data/lib/qrb/type/relation_type.rb +81 -0
- data/lib/qrb/type/seq_type.rb +51 -0
- data/lib/qrb/type/set_type.rb +52 -0
- data/lib/qrb/type/sub_type.rb +94 -0
- data/lib/qrb/type/tuple_type.rb +99 -0
- data/lib/qrb/type/union_type.rb +78 -0
- data/lib/qrb/type.rb +63 -0
- data/lib/qrb/version.rb +14 -0
- data/lib/qrb.rb +63 -0
- data/qrb.gemspec +186 -0
- data/spec/acceptance/Q/test_default.rb +96 -0
- data/spec/acceptance/Q/test_parsing.rb +15 -0
- data/spec/acceptance/ad_type/test_in_q.rb +82 -0
- data/spec/acceptance/ad_type/test_in_ruby.rb +60 -0
- data/spec/spec_helper.rb +68 -0
- data/spec/unit/attribute/test_equality.rb +26 -0
- data/spec/unit/attribute/test_fetch_on.rb +50 -0
- data/spec/unit/attribute/test_initialize.rb +13 -0
- data/spec/unit/attribute/test_to_name.rb +10 -0
- data/spec/unit/heading/test_each.rb +28 -0
- data/spec/unit/heading/test_equality.rb +28 -0
- data/spec/unit/heading/test_initialize.rb +36 -0
- data/spec/unit/heading/test_size.rb +30 -0
- data/spec/unit/heading/test_to_name.rb +32 -0
- data/spec/unit/qrb/test_parse.rb +18 -0
- data/spec/unit/syntax/nodes/test_ad_type.rb +94 -0
- data/spec/unit/syntax/nodes/test_attribute.rb +25 -0
- data/spec/unit/syntax/nodes/test_builtin_type.rb +32 -0
- data/spec/unit/syntax/nodes/test_comment.rb +26 -0
- data/spec/unit/syntax/nodes/test_constraint_def.rb +27 -0
- data/spec/unit/syntax/nodes/test_constraints.rb +51 -0
- data/spec/unit/syntax/nodes/test_contract.rb +62 -0
- data/spec/unit/syntax/nodes/test_expression.rb +43 -0
- data/spec/unit/syntax/nodes/test_heading.rb +41 -0
- data/spec/unit/syntax/nodes/test_named_constraint.rb +31 -0
- data/spec/unit/syntax/nodes/test_relation_type.rb +41 -0
- data/spec/unit/syntax/nodes/test_seq_type.rb +24 -0
- data/spec/unit/syntax/nodes/test_set_type.rb +24 -0
- data/spec/unit/syntax/nodes/test_spacing.rb +25 -0
- data/spec/unit/syntax/nodes/test_sub_type.rb +52 -0
- data/spec/unit/syntax/nodes/test_tuple_type.rb +41 -0
- data/spec/unit/syntax/nodes/test_union_type.rb +23 -0
- data/spec/unit/syntax/nodes/test_unnamed_constraint.rb +31 -0
- data/spec/unit/syntax/test_compile_type.rb +22 -0
- data/spec/unit/system/test_add_type.rb +47 -0
- data/spec/unit/system/test_dsl.rb +30 -0
- data/spec/unit/system/test_dup.rb +30 -0
- data/spec/unit/system/test_fetch.rb +42 -0
- data/spec/unit/system/test_get_type.rb +30 -0
- data/spec/unit/system/test_initialize.rb +10 -0
- data/spec/unit/test_qrb.rb +15 -0
- data/spec/unit/type/ad_type/test_default_name.rb +15 -0
- data/spec/unit/type/ad_type/test_dress.rb +55 -0
- data/spec/unit/type/ad_type/test_include.rb +22 -0
- data/spec/unit/type/ad_type/test_initialize.rb +40 -0
- data/spec/unit/type/ad_type/test_name.rb +20 -0
- data/spec/unit/type/builtin_type/test_default_name.rb +12 -0
- data/spec/unit/type/builtin_type/test_dress.rb +33 -0
- data/spec/unit/type/builtin_type/test_equality.rb +26 -0
- data/spec/unit/type/builtin_type/test_include.rb +22 -0
- data/spec/unit/type/builtin_type/test_initialize.rb +12 -0
- data/spec/unit/type/builtin_type/test_name.rb +24 -0
- data/spec/unit/type/relation_type/test_default_name.rb +16 -0
- data/spec/unit/type/relation_type/test_dress.rb +164 -0
- data/spec/unit/type/relation_type/test_equality.rb +32 -0
- data/spec/unit/type/relation_type/test_include.rb +46 -0
- data/spec/unit/type/relation_type/test_initialize.rb +26 -0
- data/spec/unit/type/relation_type/test_name.rb +24 -0
- data/spec/unit/type/seq_type/test_default_name.rb +14 -0
- data/spec/unit/type/seq_type/test_dress.rb +49 -0
- data/spec/unit/type/seq_type/test_equality.rb +26 -0
- data/spec/unit/type/seq_type/test_include.rb +43 -0
- data/spec/unit/type/seq_type/test_initialize.rb +28 -0
- data/spec/unit/type/seq_type/test_name.rb +24 -0
- data/spec/unit/type/set_type/test_default_name.rb +14 -0
- data/spec/unit/type/set_type/test_dress.rb +66 -0
- data/spec/unit/type/set_type/test_equality.rb +26 -0
- data/spec/unit/type/set_type/test_include.rb +43 -0
- data/spec/unit/type/set_type/test_initialize.rb +28 -0
- data/spec/unit/type/set_type/test_name.rb +24 -0
- data/spec/unit/type/sub_type/test_default_name.rb +14 -0
- data/spec/unit/type/sub_type/test_dress.rb +75 -0
- data/spec/unit/type/sub_type/test_equality.rb +34 -0
- data/spec/unit/type/sub_type/test_include.rb +34 -0
- data/spec/unit/type/sub_type/test_initialize.rb +16 -0
- data/spec/unit/type/sub_type/test_name.rb +24 -0
- data/spec/unit/type/tuple_type/test_default_name.rb +14 -0
- data/spec/unit/type/tuple_type/test_dress.rb +112 -0
- data/spec/unit/type/tuple_type/test_equality.rb +32 -0
- data/spec/unit/type/tuple_type/test_include.rb +38 -0
- data/spec/unit/type/tuple_type/test_initialize.rb +30 -0
- data/spec/unit/type/tuple_type/test_name.rb +24 -0
- data/spec/unit/type/union_type/test_default_name.rb +12 -0
- data/spec/unit/type/union_type/test_dress.rb +43 -0
- data/spec/unit/type/union_type/test_equality.rb +30 -0
- data/spec/unit/type/union_type/test_include.rb +28 -0
- data/spec/unit/type/union_type/test_initialize.rb +24 -0
- data/spec/unit/type/union_type/test_name.rb +20 -0
- data/spec/unit/type_factory/dsl/test_adt.rb +54 -0
- data/spec/unit/type_factory/dsl/test_attribute.rb +37 -0
- data/spec/unit/type_factory/dsl/test_attributes.rb +41 -0
- data/spec/unit/type_factory/dsl/test_builtin.rb +45 -0
- data/spec/unit/type_factory/dsl/test_relation.rb +85 -0
- data/spec/unit/type_factory/dsl/test_seq.rb +57 -0
- data/spec/unit/type_factory/dsl/test_set.rb +57 -0
- data/spec/unit/type_factory/dsl/test_subtype.rb +91 -0
- data/spec/unit/type_factory/dsl/test_tuple.rb +73 -0
- data/spec/unit/type_factory/dsl/test_union.rb +81 -0
- data/spec/unit/type_factory/factory/test_builtin.rb +24 -0
- data/spec/unit/type_factory/factory/test_seq_type.rb +44 -0
- data/spec/unit/type_factory/factory/test_set_type.rb +44 -0
- data/spec/unit/type_factory/factory/test_sub_type.rb +53 -0
- data/spec/unit/type_factory/factory/test_tuple_type.rb +43 -0
- data/tasks/gem.rake +73 -0
- data/tasks/test.rake +31 -0
- metadata +344 -0
data/lib/qrb.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
#
|
5
|
+
# Q - in Ruby
|
6
|
+
#
|
7
|
+
module Qrb
|
8
|
+
|
9
|
+
DSL_METHODS = [
|
10
|
+
:attribute,
|
11
|
+
:heading,
|
12
|
+
:constraints,
|
13
|
+
:builtin,
|
14
|
+
:adt,
|
15
|
+
:subtype,
|
16
|
+
:union,
|
17
|
+
:seq,
|
18
|
+
:set,
|
19
|
+
:tuple,
|
20
|
+
:relation,
|
21
|
+
:type
|
22
|
+
]
|
23
|
+
|
24
|
+
require_relative "qrb/version"
|
25
|
+
require_relative "qrb/errors"
|
26
|
+
require_relative "qrb/support"
|
27
|
+
require_relative 'qrb/type'
|
28
|
+
require_relative 'qrb/data_type'
|
29
|
+
require_relative 'qrb/system'
|
30
|
+
|
31
|
+
DEFAULT_FACTORY = TypeFactory.new
|
32
|
+
|
33
|
+
IDENTITY = ->(object){ object }
|
34
|
+
|
35
|
+
DSL_METHODS.each do |meth|
|
36
|
+
define_method(meth) do |*args, &bl|
|
37
|
+
DEFAULT_FACTORY.public_send(meth, *args, &bl)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse(source)
|
42
|
+
require "qrb/syntax"
|
43
|
+
Syntax.compile(source)
|
44
|
+
end
|
45
|
+
|
46
|
+
def system(identifier)
|
47
|
+
f = File.expand_path("../qrb/#{identifier}.q", __FILE__)
|
48
|
+
if File.exists?(f)
|
49
|
+
parse(File.read(f))
|
50
|
+
else
|
51
|
+
raise Error, "Unknown system #{identifier}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def definition_files(of)
|
56
|
+
dir = File.expand_path("../qrb/#{of}", __FILE__)
|
57
|
+
Dir.glob("#{dir}/*.q")
|
58
|
+
end
|
59
|
+
|
60
|
+
extend self
|
61
|
+
|
62
|
+
DEFAULT_SYSTEM = system('Q/default')
|
63
|
+
end # module Qrb
|
data/qrb.gemspec
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
# We require your library, mainly to have access to the VERSION number.
|
2
|
+
# Feel free to set $version manually.
|
3
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
4
|
+
require "qrb/version"
|
5
|
+
$version = Qrb::Version.to_s
|
6
|
+
|
7
|
+
#
|
8
|
+
# This is your Gem specification. Default values are provided so that your library
|
9
|
+
# should be correctly packaged given what you have described in the .noespec file.
|
10
|
+
#
|
11
|
+
Gem::Specification.new do |s|
|
12
|
+
|
13
|
+
################################################################### ABOUT YOUR GEM
|
14
|
+
|
15
|
+
# Gem name (required)
|
16
|
+
s.name = "qrb"
|
17
|
+
|
18
|
+
# Gem version (required)
|
19
|
+
s.version = $version
|
20
|
+
|
21
|
+
# A short summary of this gem
|
22
|
+
#
|
23
|
+
# This is displayed in `gem list -d`.
|
24
|
+
s.summary = "Q - in Ruby"
|
25
|
+
|
26
|
+
# A long description of this gem (required)
|
27
|
+
#
|
28
|
+
# The description should be more detailed than the summary. For example,
|
29
|
+
# you might wish to copy the entire README into the description.
|
30
|
+
s.description = "Implements the Q information language in Ruby."
|
31
|
+
|
32
|
+
# The URL of this gem home page (optional)
|
33
|
+
s.homepage = "https://github.com/blambeau/qrb"
|
34
|
+
|
35
|
+
# Gem publication date (required but auto)
|
36
|
+
#
|
37
|
+
# Today is automatically used by default, uncomment only if
|
38
|
+
# you know what you do!
|
39
|
+
#
|
40
|
+
# s.date = Time.now.strftime('%Y-%m-%d')
|
41
|
+
|
42
|
+
# The license(s) for the library. Each license must be a short name, no
|
43
|
+
# more than 64 characters.
|
44
|
+
#
|
45
|
+
# s.licences = %w{}
|
46
|
+
|
47
|
+
# The rubyforge project this gem lives under (optional)
|
48
|
+
#
|
49
|
+
# s.rubyforge_project = nil
|
50
|
+
|
51
|
+
################################################################### ABOUT THE AUTHORS
|
52
|
+
|
53
|
+
# The list of author names who wrote this gem.
|
54
|
+
#
|
55
|
+
# If you are providing multiple authors and multiple emails they should be
|
56
|
+
# in the same order.
|
57
|
+
#
|
58
|
+
s.authors = ["Bernard Lambeau"]
|
59
|
+
|
60
|
+
# Contact emails for this gem
|
61
|
+
#
|
62
|
+
# If you are providing multiple authors and multiple emails they should be
|
63
|
+
# in the same order.
|
64
|
+
#
|
65
|
+
# NOTE: Somewhat strangly this attribute is always singular!
|
66
|
+
# Don't replace by s.emails = ...
|
67
|
+
s.email = ["blambeau@gmail.com"]
|
68
|
+
|
69
|
+
################################################################### PATHS, FILES, BINARIES
|
70
|
+
|
71
|
+
# Paths in the gem to add to $LOAD_PATH when this gem is
|
72
|
+
# activated (required).
|
73
|
+
#
|
74
|
+
# The default 'lib' is typically sufficient.
|
75
|
+
s.require_paths = ["lib"]
|
76
|
+
|
77
|
+
# Files included in this gem.
|
78
|
+
#
|
79
|
+
# By default, we take all files included in the Manifest.txt file on root
|
80
|
+
# of the project. Entries of the manifest are interpreted as Dir[...]
|
81
|
+
# patterns so that lazy people may use wilcards like lib/**/*
|
82
|
+
#
|
83
|
+
here = File.expand_path(File.dirname(__FILE__))
|
84
|
+
s.files = File.readlines(File.join(here, 'Manifest.txt')).
|
85
|
+
inject([]){|files, pattern| files + Dir[File.join(here, pattern.strip)]}.
|
86
|
+
collect{|x| x[(1+here.size)..-1]}
|
87
|
+
|
88
|
+
# Test files included in this gem.
|
89
|
+
#
|
90
|
+
s.test_files = Dir["test/**/*"] + Dir["spec/**/*"]
|
91
|
+
|
92
|
+
# The path in the gem for executable scripts (optional)
|
93
|
+
#
|
94
|
+
s.bindir = "bin"
|
95
|
+
|
96
|
+
# Executables included in the gem.
|
97
|
+
#
|
98
|
+
s.executables = (Dir["bin/*"]).collect{|f| File.basename(f)}
|
99
|
+
|
100
|
+
################################################################### REQUIREMENTS & INSTALL
|
101
|
+
# Remember the gem version requirements operators and schemes:
|
102
|
+
# = Equals version
|
103
|
+
# != Not equal to version
|
104
|
+
# > Greater than version
|
105
|
+
# < Less than version
|
106
|
+
# >= Greater than or equal to
|
107
|
+
# <= Less than or equal to
|
108
|
+
# ~> Approximately greater than
|
109
|
+
#
|
110
|
+
# Don't forget to have a look at http://lmgtfy.com/?q=Ruby+Versioning+Policies
|
111
|
+
# for setting your gem version.
|
112
|
+
#
|
113
|
+
# For your requirements to other gems, remember that
|
114
|
+
# ">= 2.2.0" (optimistic: specify minimal version)
|
115
|
+
# ">= 2.2.0", "< 3.0" (pessimistic: not greater than the next major)
|
116
|
+
# "~> 2.2" (shortcut for ">= 2.2.0", "< 3.0")
|
117
|
+
# "~> 2.2.0" (shortcut for ">= 2.2.0", "< 2.3.0")
|
118
|
+
#
|
119
|
+
|
120
|
+
#
|
121
|
+
# One call to add_dependency('gem_name', 'gem version requirement') for each
|
122
|
+
# runtime dependency. These gems will be installed with your gem.
|
123
|
+
# One call to add_development_dependency('gem_name', 'gem version requirement')
|
124
|
+
# for each development dependency. These gems are required for developers
|
125
|
+
#
|
126
|
+
s.add_development_dependency("rake", "~> 10.0")
|
127
|
+
s.add_development_dependency("rspec", "~> 2.14")
|
128
|
+
|
129
|
+
|
130
|
+
# The version of ruby required by this gem
|
131
|
+
#
|
132
|
+
# Uncomment and set this if your gem requires specific ruby versions.
|
133
|
+
#
|
134
|
+
# s.required_ruby_version = ">= 0"
|
135
|
+
|
136
|
+
# The RubyGems version required by this gem
|
137
|
+
#
|
138
|
+
# s.required_rubygems_version = ">= 0"
|
139
|
+
|
140
|
+
# The platform this gem runs on. See Gem::Platform for details.
|
141
|
+
#
|
142
|
+
# s.platform = nil
|
143
|
+
|
144
|
+
# Extensions to build when installing the gem.
|
145
|
+
#
|
146
|
+
# Valid types of extensions are extconf.rb files, configure scripts
|
147
|
+
# and rakefiles or mkrf_conf files.
|
148
|
+
#
|
149
|
+
s.extensions = []
|
150
|
+
|
151
|
+
# External (to RubyGems) requirements that must be met for this gem to work.
|
152
|
+
# It’s simply information for the user.
|
153
|
+
#
|
154
|
+
s.requirements = nil
|
155
|
+
|
156
|
+
# A message that gets displayed after the gem is installed
|
157
|
+
#
|
158
|
+
# Uncomment and set this if you want to say something to the user
|
159
|
+
# after gem installation
|
160
|
+
#
|
161
|
+
s.post_install_message = nil
|
162
|
+
|
163
|
+
################################################################### SECURITY
|
164
|
+
|
165
|
+
# The key used to sign this gem. See Gem::Security for details.
|
166
|
+
#
|
167
|
+
# s.signing_key = nil
|
168
|
+
|
169
|
+
# The certificate chain used to sign this gem. See Gem::Security for
|
170
|
+
# details.
|
171
|
+
#
|
172
|
+
# s.cert_chain = []
|
173
|
+
|
174
|
+
################################################################### RDOC
|
175
|
+
|
176
|
+
# An ARGV style array of options to RDoc
|
177
|
+
#
|
178
|
+
# See 'rdoc --help' about this
|
179
|
+
#
|
180
|
+
s.rdoc_options = []
|
181
|
+
|
182
|
+
# Extra files to add to RDoc such as README
|
183
|
+
#
|
184
|
+
s.extra_rdoc_files = Dir["README.md"] + Dir["CHANGELOG.md"] + Dir["LICENCE.md"]
|
185
|
+
|
186
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe "Q/default" do
|
4
|
+
|
5
|
+
let(:system){ Qrb.system('Q/default') }
|
6
|
+
|
7
|
+
describe 'Boolean' do
|
8
|
+
let(:type){ system['Boolean'] }
|
9
|
+
|
10
|
+
it 'recognizes true' do
|
11
|
+
type.dress(true).should eq(true)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'recognizes false' do
|
15
|
+
type.dress(false).should eq(false)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'raises on something else' do
|
19
|
+
->{ type.dress("foo") }.should raise_error(TypeError)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'Date' do
|
24
|
+
let(:type){ system['Date'] }
|
25
|
+
|
26
|
+
let(:expected){ Date.new(2014, 11, 9) }
|
27
|
+
|
28
|
+
it 'recognizes dates' do
|
29
|
+
type.dress(expected).should be(expected)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'recognizes iso8601 dates' do
|
33
|
+
type.dress('2014-11-09').should eq(expected)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'recognizes the output of iso8601' do
|
37
|
+
type.dress(expected.iso8601).should eq(expected)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'raises on something else' do
|
41
|
+
->{
|
42
|
+
type.dress('foo')
|
43
|
+
}.should raise_error("Invalid value `foo` for Date")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'Time' do
|
48
|
+
let(:type){ system['Time'] }
|
49
|
+
|
50
|
+
let(:expected){ Time.new(2014,3,1,12,9,31) }
|
51
|
+
|
52
|
+
it 'recognizes times' do
|
53
|
+
type.dress(expected).should be(expected)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'recognizes iso8601 times' do
|
57
|
+
type.dress('2014-03-01T12:09:31').should eq(expected)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'recognizes the output of iso8601' do
|
61
|
+
type.dress(expected.iso8601).should eq(expected)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'raises on something else' do
|
65
|
+
->{
|
66
|
+
type.dress('foo')
|
67
|
+
}.should raise_error("Invalid value `foo` for Time")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'DateTime' do
|
72
|
+
let(:type){ system['DateTime'] }
|
73
|
+
|
74
|
+
let(:expected){ DateTime.new(2014,3,1,12,9,31) }
|
75
|
+
|
76
|
+
it 'recognizes times' do
|
77
|
+
type.dress(expected).should be(expected)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'recognizes iso8601 times' do
|
81
|
+
type.dress('2014-03-01T12:09:31').should eq(expected)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'recognizes the output of iso8601' do
|
85
|
+
type.dress(expected.iso8601).should eq(expected)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'raises on something else' do
|
89
|
+
->{
|
90
|
+
type.dress('foo')
|
91
|
+
}.should raise_error("Invalid value `foo` for DateTime")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe "Q definition files" do
|
3
|
+
|
4
|
+
Qrb.definition_files('Q').each do |file|
|
5
|
+
file = Path(file)
|
6
|
+
|
7
|
+
describe "Q/#{file.basename.rm_ext}" do
|
8
|
+
|
9
|
+
it 'should parse' do
|
10
|
+
Qrb.parse(file.read).should be_a(Qrb::System)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe "Using Q's abstract data types in Ruby/Q" do
|
4
|
+
|
5
|
+
class MyColorClass
|
6
|
+
extend Qrb::DataType
|
7
|
+
|
8
|
+
def initialize(r, g, b)
|
9
|
+
@r, @g, @b = r, g, b
|
10
|
+
end
|
11
|
+
attr_reader :r, :g, :b
|
12
|
+
|
13
|
+
def to_rgb
|
14
|
+
{ r: @r, g: @g, b: @b }
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.rgb(tuple)
|
18
|
+
new(tuple[:r], tuple[:g], tuple[:b])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:system) do
|
23
|
+
Qrb.parse <<-EOF
|
24
|
+
Byte = .Fixnum( i | i>=0 and i<= 255 )
|
25
|
+
Color = .Qrb::MyColorClass <rgb> {r: Byte, g: Byte, b: Byte}
|
26
|
+
Gender = <mf> .String( s | s=='M' or s=='F' )
|
27
|
+
EOF
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:color){
|
31
|
+
system["Color"]
|
32
|
+
}
|
33
|
+
|
34
|
+
describe 'the Color.dress method' do
|
35
|
+
subject{ color.dress(arg) }
|
36
|
+
|
37
|
+
context 'when valid' do
|
38
|
+
let(:arg){ {"r" => 12, "g" => 17, "b" => 71} }
|
39
|
+
|
40
|
+
it{ should be_a(MyColorClass) }
|
41
|
+
|
42
|
+
it 'should be the expected one' do
|
43
|
+
subject.r.should eq(12)
|
44
|
+
subject.g.should eq(17)
|
45
|
+
subject.b.should eq(71)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when invalid' do
|
50
|
+
let(:arg){ {"r" => -12, "g" => 17, "b" => 71} }
|
51
|
+
|
52
|
+
it 'should raise an error' do
|
53
|
+
->{
|
54
|
+
subject
|
55
|
+
}.should raise_error(TypeError)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'the Gender.dress method' do
|
62
|
+
subject{ system['Gender'].dress(arg) }
|
63
|
+
|
64
|
+
context 'when valid' do
|
65
|
+
let(:arg){ 'M' }
|
66
|
+
|
67
|
+
it{ should eq('M') }
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when valid' do
|
71
|
+
let(:arg){ 'Monsieur' }
|
72
|
+
|
73
|
+
it 'should raise an error' do
|
74
|
+
->{
|
75
|
+
subject
|
76
|
+
}.should raise_error(TypeError, "Invalid value `Monsieur` for Gender")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe "Using Q's abstract data types in Ruby" do
|
4
|
+
|
5
|
+
let(:color) do
|
6
|
+
Class.new{
|
7
|
+
extend Qrb::DataType
|
8
|
+
|
9
|
+
def initialize(r, g, b)
|
10
|
+
@r, @g, @b = r, g, b
|
11
|
+
end
|
12
|
+
attr_reader :r, :g, :b
|
13
|
+
|
14
|
+
def to_rgb
|
15
|
+
{ r: @r, g: @g, b: @b }
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.rgb(tuple)
|
19
|
+
new(tuple[:r], tuple[:g], tuple[:b])
|
20
|
+
end
|
21
|
+
|
22
|
+
contract :rgb, {r: 0..255, g: 0..255, b: 0..255}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'The factored class' do
|
27
|
+
subject{ color }
|
28
|
+
|
29
|
+
it{ should be_a(Class) }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'the dress method, when valid' do
|
33
|
+
|
34
|
+
subject{
|
35
|
+
color.dress(r: 12, g: 13, b: 28)
|
36
|
+
}
|
37
|
+
|
38
|
+
it{ should be_a(color) }
|
39
|
+
|
40
|
+
it 'should set the instance variables correctly' do
|
41
|
+
subject.r.should eq(12)
|
42
|
+
subject.g.should eq(13)
|
43
|
+
subject.b.should eq(28)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'the up method, when already a color' do
|
48
|
+
let(:value){
|
49
|
+
color.new(12, 13, 28)
|
50
|
+
}
|
51
|
+
|
52
|
+
subject{
|
53
|
+
color.dress(value)
|
54
|
+
}
|
55
|
+
|
56
|
+
it{ should be(value) }
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'path'
|
3
|
+
require 'qrb'
|
4
|
+
require 'qrb/syntax'
|
5
|
+
|
6
|
+
require 'coveralls'
|
7
|
+
Coveralls.wear!
|
8
|
+
|
9
|
+
class Color
|
10
|
+
|
11
|
+
def initialize(r, g, b)
|
12
|
+
@r, @g, @b = r, g, b
|
13
|
+
end
|
14
|
+
attr_reader :r, :g, :b
|
15
|
+
|
16
|
+
def self.rgb(tuple)
|
17
|
+
new(tuple[:r], tuple[:g], tuple[:b])
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_rgb
|
21
|
+
{ r: @r, g: @g, b: @b }
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.hex(s)
|
25
|
+
Color.new *[1, 3, 5].map{|i| s[i, 2].to_i(16) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_hex
|
29
|
+
"#" << [r, g, b].map{|i| i.to_s(16) }.join
|
30
|
+
end
|
31
|
+
|
32
|
+
def ==(other)
|
33
|
+
other.is_a?(Color) and other.to_rgb == self.to_rgb
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
module SpecHelpers
|
39
|
+
|
40
|
+
def intType
|
41
|
+
Qrb::BuiltinType.new(Integer, "intType")
|
42
|
+
end
|
43
|
+
|
44
|
+
def floatType
|
45
|
+
Qrb::BuiltinType.new(Float, "floatType")
|
46
|
+
end
|
47
|
+
|
48
|
+
def nilType
|
49
|
+
Qrb::BuiltinType.new(NilClass, "nilType")
|
50
|
+
end
|
51
|
+
|
52
|
+
def byte
|
53
|
+
Qrb::SubType.new(intType, byte: ->(i){ i>=0 && i<=255 })
|
54
|
+
end
|
55
|
+
|
56
|
+
def type_factory
|
57
|
+
Qrb::TypeFactory.new
|
58
|
+
end
|
59
|
+
|
60
|
+
def blueviolet
|
61
|
+
Color.new(138, 43, 226)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
RSpec.configure do |c|
|
67
|
+
c.include SpecHelpers
|
68
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Attribute, "equality" do
|
4
|
+
|
5
|
+
let(:attr1){ Attribute.new(:red, intType) }
|
6
|
+
let(:attr2){ Attribute.new(:red, intType) }
|
7
|
+
let(:attr3){ Attribute.new(:blue, intType) }
|
8
|
+
|
9
|
+
it 'should apply structural equality' do
|
10
|
+
(attr1 == attr2).should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should distinguish different attributes' do
|
14
|
+
(attr1 == attr3).should be_false
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return nil if not equal' do
|
18
|
+
(attr1 == 12).should be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should implement hash accordingly' do
|
22
|
+
attr1.hash.should eq(attr2.hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Attribute, "fetch_on" do
|
4
|
+
|
5
|
+
let(:attr){ Attribute.new(:red, intType) }
|
6
|
+
|
7
|
+
subject{ attr.fetch_on(arg) }
|
8
|
+
|
9
|
+
context 'with an object that does not support fetch' do
|
10
|
+
let(:arg){ 12 }
|
11
|
+
|
12
|
+
it 'should raise an error' do
|
13
|
+
->{
|
14
|
+
subject
|
15
|
+
}.should raise_error(ArgumentError, "Object responding to `fetch` expected")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with a hash with symbol keys' do
|
20
|
+
let(:arg){ { red: 233 } }
|
21
|
+
|
22
|
+
it{ should eq(233) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with a hash with string keys' do
|
26
|
+
let(:arg){ { "red" => 233 } }
|
27
|
+
|
28
|
+
it{ should eq(233) }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when the key is missing and no block' do
|
32
|
+
let(:arg){ { other: 123 } }
|
33
|
+
|
34
|
+
it 'should raise an error' do
|
35
|
+
->{
|
36
|
+
attr.fetch_on(arg)
|
37
|
+
}.should raise_error(KeyError)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when the key is missing and a block' do
|
42
|
+
let(:arg){ { other: 123 } }
|
43
|
+
|
44
|
+
it 'should yield the block' do
|
45
|
+
attr.fetch_on(arg){ "none" }.should eq("none")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Attribute, "initialize" do
|
4
|
+
|
5
|
+
subject{ Attribute.new(:red, intType) }
|
6
|
+
|
7
|
+
it 'should correctly set the instance variables' do
|
8
|
+
subject.name.should eq(:red)
|
9
|
+
subject.type.should eq(intType)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Qrb
|
3
|
+
describe Heading, "each" do
|
4
|
+
|
5
|
+
let(:a){ Attribute.new(:a, intType) }
|
6
|
+
let(:b){ Attribute.new(:b, intType) }
|
7
|
+
let(:h){ Heading.new([a, b]) }
|
8
|
+
|
9
|
+
context 'without a block' do
|
10
|
+
|
11
|
+
it 'should return an enumerator' do
|
12
|
+
h.each.should be_a(Enumerator)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with a block' do
|
17
|
+
|
18
|
+
it 'should yield each attribute in turn' do
|
19
|
+
seen = []
|
20
|
+
h.each do |attr|
|
21
|
+
seen << attr
|
22
|
+
end
|
23
|
+
seen.should eq([a, b])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|