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.
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