qrb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|