qrb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/Gemfile +12 -0
  3. data/Gemfile.lock +58 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +11 -0
  6. data/README.md +118 -0
  7. data/Rakefile +11 -0
  8. data/lib/qrb/Q/default.q +29 -0
  9. data/lib/qrb/data_type.rb +23 -0
  10. data/lib/qrb/errors.rb +23 -0
  11. data/lib/qrb/support/attribute.rb +53 -0
  12. data/lib/qrb/support/collection_type.rb +25 -0
  13. data/lib/qrb/support/dress_helper.rb +68 -0
  14. data/lib/qrb/support/heading.rb +57 -0
  15. data/lib/qrb/support/type_factory.rb +178 -0
  16. data/lib/qrb/support.rb +5 -0
  17. data/lib/qrb/syntax/ad_type.rb +25 -0
  18. data/lib/qrb/syntax/attribute.rb +11 -0
  19. data/lib/qrb/syntax/builtin_type.rb +13 -0
  20. data/lib/qrb/syntax/constraint_def.rb +11 -0
  21. data/lib/qrb/syntax/constraints.rb +18 -0
  22. data/lib/qrb/syntax/contract.rb +25 -0
  23. data/lib/qrb/syntax/definitions.rb +14 -0
  24. data/lib/qrb/syntax/expression.rb +12 -0
  25. data/lib/qrb/syntax/heading.rb +15 -0
  26. data/lib/qrb/syntax/lambda_expr.rb +11 -0
  27. data/lib/qrb/syntax/named_constraint.rb +11 -0
  28. data/lib/qrb/syntax/q.citrus +195 -0
  29. data/lib/qrb/syntax/relation_type.rb +11 -0
  30. data/lib/qrb/syntax/seq_type.rb +12 -0
  31. data/lib/qrb/syntax/set_type.rb +12 -0
  32. data/lib/qrb/syntax/sub_type.rb +13 -0
  33. data/lib/qrb/syntax/support.rb +13 -0
  34. data/lib/qrb/syntax/system.rb +15 -0
  35. data/lib/qrb/syntax/tuple_type.rb +11 -0
  36. data/lib/qrb/syntax/type_def.rb +14 -0
  37. data/lib/qrb/syntax/type_ref.rb +13 -0
  38. data/lib/qrb/syntax/union_type.rb +12 -0
  39. data/lib/qrb/syntax/unnamed_constraint.rb +11 -0
  40. data/lib/qrb/syntax.rb +42 -0
  41. data/lib/qrb/system.rb +63 -0
  42. data/lib/qrb/type/ad_type.rb +111 -0
  43. data/lib/qrb/type/builtin_type.rb +56 -0
  44. data/lib/qrb/type/relation_type.rb +81 -0
  45. data/lib/qrb/type/seq_type.rb +51 -0
  46. data/lib/qrb/type/set_type.rb +52 -0
  47. data/lib/qrb/type/sub_type.rb +94 -0
  48. data/lib/qrb/type/tuple_type.rb +99 -0
  49. data/lib/qrb/type/union_type.rb +78 -0
  50. data/lib/qrb/type.rb +63 -0
  51. data/lib/qrb/version.rb +14 -0
  52. data/lib/qrb.rb +63 -0
  53. data/qrb.gemspec +186 -0
  54. data/spec/acceptance/Q/test_default.rb +96 -0
  55. data/spec/acceptance/Q/test_parsing.rb +15 -0
  56. data/spec/acceptance/ad_type/test_in_q.rb +82 -0
  57. data/spec/acceptance/ad_type/test_in_ruby.rb +60 -0
  58. data/spec/spec_helper.rb +68 -0
  59. data/spec/unit/attribute/test_equality.rb +26 -0
  60. data/spec/unit/attribute/test_fetch_on.rb +50 -0
  61. data/spec/unit/attribute/test_initialize.rb +13 -0
  62. data/spec/unit/attribute/test_to_name.rb +10 -0
  63. data/spec/unit/heading/test_each.rb +28 -0
  64. data/spec/unit/heading/test_equality.rb +28 -0
  65. data/spec/unit/heading/test_initialize.rb +36 -0
  66. data/spec/unit/heading/test_size.rb +30 -0
  67. data/spec/unit/heading/test_to_name.rb +32 -0
  68. data/spec/unit/qrb/test_parse.rb +18 -0
  69. data/spec/unit/syntax/nodes/test_ad_type.rb +94 -0
  70. data/spec/unit/syntax/nodes/test_attribute.rb +25 -0
  71. data/spec/unit/syntax/nodes/test_builtin_type.rb +32 -0
  72. data/spec/unit/syntax/nodes/test_comment.rb +26 -0
  73. data/spec/unit/syntax/nodes/test_constraint_def.rb +27 -0
  74. data/spec/unit/syntax/nodes/test_constraints.rb +51 -0
  75. data/spec/unit/syntax/nodes/test_contract.rb +62 -0
  76. data/spec/unit/syntax/nodes/test_expression.rb +43 -0
  77. data/spec/unit/syntax/nodes/test_heading.rb +41 -0
  78. data/spec/unit/syntax/nodes/test_named_constraint.rb +31 -0
  79. data/spec/unit/syntax/nodes/test_relation_type.rb +41 -0
  80. data/spec/unit/syntax/nodes/test_seq_type.rb +24 -0
  81. data/spec/unit/syntax/nodes/test_set_type.rb +24 -0
  82. data/spec/unit/syntax/nodes/test_spacing.rb +25 -0
  83. data/spec/unit/syntax/nodes/test_sub_type.rb +52 -0
  84. data/spec/unit/syntax/nodes/test_tuple_type.rb +41 -0
  85. data/spec/unit/syntax/nodes/test_union_type.rb +23 -0
  86. data/spec/unit/syntax/nodes/test_unnamed_constraint.rb +31 -0
  87. data/spec/unit/syntax/test_compile_type.rb +22 -0
  88. data/spec/unit/system/test_add_type.rb +47 -0
  89. data/spec/unit/system/test_dsl.rb +30 -0
  90. data/spec/unit/system/test_dup.rb +30 -0
  91. data/spec/unit/system/test_fetch.rb +42 -0
  92. data/spec/unit/system/test_get_type.rb +30 -0
  93. data/spec/unit/system/test_initialize.rb +10 -0
  94. data/spec/unit/test_qrb.rb +15 -0
  95. data/spec/unit/type/ad_type/test_default_name.rb +15 -0
  96. data/spec/unit/type/ad_type/test_dress.rb +55 -0
  97. data/spec/unit/type/ad_type/test_include.rb +22 -0
  98. data/spec/unit/type/ad_type/test_initialize.rb +40 -0
  99. data/spec/unit/type/ad_type/test_name.rb +20 -0
  100. data/spec/unit/type/builtin_type/test_default_name.rb +12 -0
  101. data/spec/unit/type/builtin_type/test_dress.rb +33 -0
  102. data/spec/unit/type/builtin_type/test_equality.rb +26 -0
  103. data/spec/unit/type/builtin_type/test_include.rb +22 -0
  104. data/spec/unit/type/builtin_type/test_initialize.rb +12 -0
  105. data/spec/unit/type/builtin_type/test_name.rb +24 -0
  106. data/spec/unit/type/relation_type/test_default_name.rb +16 -0
  107. data/spec/unit/type/relation_type/test_dress.rb +164 -0
  108. data/spec/unit/type/relation_type/test_equality.rb +32 -0
  109. data/spec/unit/type/relation_type/test_include.rb +46 -0
  110. data/spec/unit/type/relation_type/test_initialize.rb +26 -0
  111. data/spec/unit/type/relation_type/test_name.rb +24 -0
  112. data/spec/unit/type/seq_type/test_default_name.rb +14 -0
  113. data/spec/unit/type/seq_type/test_dress.rb +49 -0
  114. data/spec/unit/type/seq_type/test_equality.rb +26 -0
  115. data/spec/unit/type/seq_type/test_include.rb +43 -0
  116. data/spec/unit/type/seq_type/test_initialize.rb +28 -0
  117. data/spec/unit/type/seq_type/test_name.rb +24 -0
  118. data/spec/unit/type/set_type/test_default_name.rb +14 -0
  119. data/spec/unit/type/set_type/test_dress.rb +66 -0
  120. data/spec/unit/type/set_type/test_equality.rb +26 -0
  121. data/spec/unit/type/set_type/test_include.rb +43 -0
  122. data/spec/unit/type/set_type/test_initialize.rb +28 -0
  123. data/spec/unit/type/set_type/test_name.rb +24 -0
  124. data/spec/unit/type/sub_type/test_default_name.rb +14 -0
  125. data/spec/unit/type/sub_type/test_dress.rb +75 -0
  126. data/spec/unit/type/sub_type/test_equality.rb +34 -0
  127. data/spec/unit/type/sub_type/test_include.rb +34 -0
  128. data/spec/unit/type/sub_type/test_initialize.rb +16 -0
  129. data/spec/unit/type/sub_type/test_name.rb +24 -0
  130. data/spec/unit/type/tuple_type/test_default_name.rb +14 -0
  131. data/spec/unit/type/tuple_type/test_dress.rb +112 -0
  132. data/spec/unit/type/tuple_type/test_equality.rb +32 -0
  133. data/spec/unit/type/tuple_type/test_include.rb +38 -0
  134. data/spec/unit/type/tuple_type/test_initialize.rb +30 -0
  135. data/spec/unit/type/tuple_type/test_name.rb +24 -0
  136. data/spec/unit/type/union_type/test_default_name.rb +12 -0
  137. data/spec/unit/type/union_type/test_dress.rb +43 -0
  138. data/spec/unit/type/union_type/test_equality.rb +30 -0
  139. data/spec/unit/type/union_type/test_include.rb +28 -0
  140. data/spec/unit/type/union_type/test_initialize.rb +24 -0
  141. data/spec/unit/type/union_type/test_name.rb +20 -0
  142. data/spec/unit/type_factory/dsl/test_adt.rb +54 -0
  143. data/spec/unit/type_factory/dsl/test_attribute.rb +37 -0
  144. data/spec/unit/type_factory/dsl/test_attributes.rb +41 -0
  145. data/spec/unit/type_factory/dsl/test_builtin.rb +45 -0
  146. data/spec/unit/type_factory/dsl/test_relation.rb +85 -0
  147. data/spec/unit/type_factory/dsl/test_seq.rb +57 -0
  148. data/spec/unit/type_factory/dsl/test_set.rb +57 -0
  149. data/spec/unit/type_factory/dsl/test_subtype.rb +91 -0
  150. data/spec/unit/type_factory/dsl/test_tuple.rb +73 -0
  151. data/spec/unit/type_factory/dsl/test_union.rb +81 -0
  152. data/spec/unit/type_factory/factory/test_builtin.rb +24 -0
  153. data/spec/unit/type_factory/factory/test_seq_type.rb +44 -0
  154. data/spec/unit/type_factory/factory/test_set_type.rb +44 -0
  155. data/spec/unit/type_factory/factory/test_sub_type.rb +53 -0
  156. data/spec/unit/type_factory/factory/test_tuple_type.rb +43 -0
  157. data/tasks/gem.rake +73 -0
  158. data/tasks/test.rake +31 -0
  159. 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
@@ -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,10 @@
1
+ require 'spec_helper'
2
+ module Qrb
3
+ describe Attribute, "to_name" do
4
+
5
+ subject{ Attribute.new(:red, intType).to_name }
6
+
7
+ it{ should eq("red: intType") }
8
+
9
+ end
10
+ 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