rxrb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7ce3b12565242d7718c85ad989b48f551687376bc81a5b1f78d2c8a232712be1
4
+ data.tar.gz: 52e99519203ed8b2bdb05c2ae859c44f54e96216bdf59a038bf060334b818247
5
+ SHA512:
6
+ metadata.gz: f2d4151217e27f46b23220e24232a9cdbfc255d25b02c6235d6d8e0c028e4145e8e79a58a2a29d8a6649f9d1a81b43e613a1404f4bfc412f2b54dbe4d018eced
7
+ data.tar.gz: ab3acb20d831206be0fe5c857bd042e100bfeaa09c4647b5dae5db602bcb0d678476b71f922863dd9e579a4eb63ae721b48f97e9dd9e342047359ac8dc9f7ec1
@@ -0,0 +1,62 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ *.gem
14
+ *.rbc
15
+ /.config
16
+ /coverage/
17
+ /InstalledFiles
18
+ /pkg/
19
+ /spec/reports/
20
+ /spec/examples.txt
21
+ /test/tmp/
22
+ /test/version_tmp/
23
+ /tmp/
24
+
25
+ # Used by dotenv library to load environment variables.
26
+ # .env
27
+
28
+ ## Specific to RubyMotion:
29
+ .dat*
30
+ .repl_history
31
+ build/
32
+ *.bridgesupport
33
+ build-iPhoneOS/
34
+ build-iPhoneSimulator/
35
+
36
+ ## Specific to RubyMotion (use of CocoaPods):
37
+ #
38
+ # We recommend against adding the Pods directory to your .gitignore. However
39
+ # you should judge for yourself, the pros and cons are mentioned at:
40
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
41
+ #
42
+ # vendor/Pods/
43
+
44
+ ## Documentation cache and generated files:
45
+ /.yardoc/
46
+ /_yardoc/
47
+ /doc/
48
+ /rdoc/
49
+
50
+ ## Environment normalization:
51
+ /.bundle/
52
+ /vendor/bundle
53
+ /lib/bundler/man/
54
+
55
+ # for a library or gem, you might want to ignore these files since the code is
56
+ # intended to run in multiple environments; otherwise, check them in:
57
+ # Gemfile.lock
58
+ # .ruby-version
59
+ # .ruby-gemset
60
+
61
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
62
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.3
7
+ before_install: gem install bundler -v 1.16.6
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at omar.bohsali@coinbase.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in rxrb.gemspec
6
+ gemspec
@@ -0,0 +1,35 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rxrb (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.3)
10
+ rake (10.5.0)
11
+ rspec (3.8.0)
12
+ rspec-core (~> 3.8.0)
13
+ rspec-expectations (~> 3.8.0)
14
+ rspec-mocks (~> 3.8.0)
15
+ rspec-core (3.8.0)
16
+ rspec-support (~> 3.8.0)
17
+ rspec-expectations (3.8.2)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.8.0)
20
+ rspec-mocks (3.8.0)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.8.0)
23
+ rspec-support (3.8.0)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 1.16)
30
+ rake (~> 10.0)
31
+ rspec (~> 3.2)
32
+ rxrb!
33
+
34
+ BUNDLED WITH
35
+ 1.16.6
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Omar Bohsali
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,45 @@
1
+ # Rxrb
2
+
3
+ Port of: https://github.com/rjbs/Rx/tree/master/ruby
4
+
5
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rxrb`. To experiment with that code, run `bin/console` for an interactive prompt.
6
+
7
+ TODO: Delete this and the text above, and describe your gem
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'rxrb'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install rxrb
24
+
25
+ ## Usage
26
+
27
+ TODO: Write usage instructions here
28
+
29
+ ## Development
30
+
31
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
32
+
33
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
34
+
35
+ ## Contributing
36
+
37
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rxrb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
38
+
39
+ ## License
40
+
41
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
42
+
43
+ ## Code of Conduct
44
+
45
+ Everyone interacting in the Rxrb project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/rxrb/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "rxrb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,8 @@
1
+ require "rxrb/version"
2
+
3
+ module Rxrb
4
+ require 'rxrb/rx'
5
+ require 'rxrb/rx/helper'
6
+ require 'rxrb/rx/type'
7
+ require 'rxrb/rx/type/core'
8
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rxrb
4
+ class Rx
5
+ def self.schema(schema)
6
+ Rx.new(load_core: true).make_schema(schema)
7
+ end
8
+
9
+ def initialize(opt = {})
10
+ @type_registry = {}
11
+ @prefix = {
12
+ '' => 'tag:codesimply.com,2008:rx/core/',
13
+ '.meta' => 'tag:codesimply.com,2008:rx/meta/'
14
+ }
15
+
16
+ Type::Core.core_types.each { |t| register_type(t) } if opt[:load_core]
17
+ end
18
+
19
+ def register_type(type)
20
+ uri = type.uri
21
+
22
+ if @type_registry.key?(uri)
23
+ raise Rx::Exception, "attempted to register already-known type #{uri}"
24
+ end
25
+
26
+ @type_registry[uri] = type
27
+ end
28
+
29
+ def learn_type(uri, schema)
30
+ if @type_registry.key?(uri)
31
+ raise Rx::Exception, "attempted to learn type for already-registered uri #{uri}"
32
+ end
33
+
34
+ # make sure schema is valid
35
+ # should this be in a begin/rescue?
36
+ make_schema(schema)
37
+
38
+ @type_registry[uri] = { 'schema' => schema }
39
+ end
40
+
41
+ def expand_uri(name)
42
+ return name if /\A\w+:/.match?(name)
43
+
44
+ match = name.match(/\A\/(.*?)\/(.+)\z/)
45
+ unless match
46
+ raise Rx::Exception, "couldn't understand Rx type name: #{name}"
47
+ end
48
+
49
+ unless @prefix.key?(match[1])
50
+ raise Rx::Exception, "unknown prefix '#{match[1]}' in name 'name'"
51
+ end
52
+
53
+ @prefix[ match[1] ] + match[2]
54
+ end
55
+
56
+ def add_prefix(name, base)
57
+ if @prefix.key?(name)
58
+ throw Rx::Exception.new("the prefix '#{name}' is already registered")
59
+ end
60
+
61
+ @prefix[name] = base
62
+ end
63
+
64
+ def make_schema(schema)
65
+ schema = { 'type' => schema } if schema.instance_of?(String)
66
+
67
+ unless schema.instance_of?(Hash) && schema['type']
68
+ raise Rx::Exception, 'invalid type'
69
+ end
70
+
71
+ uri = expand_uri(schema['type'])
72
+
73
+ raise Rx::Exception, 'unknown type' unless @type_registry.key?(uri)
74
+
75
+ type_class = @type_registry[uri]
76
+
77
+ if type_class.instance_of?(Hash)
78
+ if schema.keys != ['type']
79
+ raise Rx::Exception, 'composed type does not take check arguments'
80
+ end
81
+ return make_schema(type_class['schema'])
82
+ else
83
+ return type_class.new(schema, self)
84
+ end
85
+ end
86
+
87
+ class Exception < StandardError
88
+ end
89
+
90
+ class ValidationError < StandardError
91
+ attr_accessor :path
92
+
93
+ def initialize(message, path)
94
+ @message = message
95
+ @path = path
96
+ end
97
+
98
+ def path
99
+ @path ||= ''
100
+ end
101
+
102
+ def message
103
+ "#{@message} (#{@path})"
104
+ end
105
+
106
+ def inspect
107
+ "#{@message} (#{@path})"
108
+ end
109
+
110
+ def to_s
111
+ inspect
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,28 @@
1
+ module Rxrb
2
+ class Rx
3
+ class Helper
4
+ end
5
+
6
+ class Helper::Range
7
+ def initialize(arg)
8
+ @range = {}
9
+
10
+ arg.each_pair do |key, value|
11
+ unless ['min', 'max', 'min-ex', 'max-ex'].index(key)
12
+ raise Rx::Exception, 'illegal argument for Rx::Helper::Range'
13
+ end
14
+
15
+ @range[key] = value
16
+ end
17
+ end
18
+
19
+ def check(value)
20
+ return false if !@range['min'].nil? && (value < @range['min'])
21
+ return false if !@range['min-ex'].nil? && (value <= @range['min-ex'])
22
+ return false if !@range['max-ex'].nil? && (value >= @range['max-ex'])
23
+ return false if !@range['max'].nil? && (value > @range['max'])
24
+ true
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ module Rxrb
2
+ class Rx
3
+ class Type
4
+ def initialize(param, _rx)
5
+ assert_valid_params(param)
6
+ end
7
+
8
+ def uri
9
+ self.class.uri
10
+ end
11
+
12
+ def assert_valid_params(param)
13
+ param.each_key do |k|
14
+ unless allowed_param?(k)
15
+ raise Rx::Exception, "unknown parameter #{k} for #{uri}"
16
+ end
17
+ end
18
+ end
19
+
20
+ module NoParams
21
+ def initialize(param, _rx)
22
+ return if param.keys.empty?
23
+ return if param.keys == ['type']
24
+
25
+ raise Rx::Exception, 'this type is not parameterized'
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,583 @@
1
+ module Rxrb
2
+ class Rx
3
+ class Type::Core < Type
4
+ class << self
5
+ def uri
6
+ 'tag:codesimply.com,2008:rx/core/' + subname
7
+ end
8
+ end
9
+
10
+ def check(value)
11
+ check!(value)
12
+ true
13
+ rescue ValidationError
14
+ false
15
+ end
16
+
17
+ class All < Type::Core
18
+ @@allowed_param = { 'of' => true, 'type' => true }
19
+ def allowed_param?(p)
20
+ @@allowed_param[p]
21
+ end
22
+
23
+ def initialize(param, rx)
24
+ super
25
+
26
+ unless param.key?('of')
27
+ raise Rx::Exception, "no 'of' parameter provided for #{uri}"
28
+ end
29
+
30
+ if param['of'].empty?
31
+ raise Rx::Exception, "no schemata provided for 'of' in #{uri}"
32
+ end
33
+
34
+ @alts = []
35
+ param['of'].each { |alt| @alts.push(rx.make_schema(alt)) }
36
+ end
37
+
38
+ class << self
39
+ def subname
40
+ 'all'
41
+ end
42
+ end
43
+
44
+ def check!(value)
45
+ @alts.each do |alt|
46
+ alt.check!(value)
47
+ rescue ValidationError => e
48
+ e.path = '/all' + e.path
49
+ raise e
50
+ end
51
+ true
52
+ end
53
+ end
54
+
55
+ class Any < Type::Core
56
+ @@allowed_param = { 'of' => true, 'type' => true }
57
+ def allowed_param?(p)
58
+ @@allowed_param[p]
59
+ end
60
+
61
+ def initialize(param, rx)
62
+ super
63
+
64
+ if param['of']
65
+ if param['of'].empty?
66
+ raise Rx::Exception, "no alternatives provided for 'of' in #{uri}"
67
+ end
68
+
69
+ @alts = []
70
+ param['of'].each { |alt| @alts.push(rx.make_schema(alt)) }
71
+ end
72
+ end
73
+
74
+ class << self
75
+ def subname
76
+ 'any'
77
+ end
78
+ end
79
+
80
+ def check!(value)
81
+ return true unless @alts
82
+
83
+ @alts.each do |alt|
84
+ return true if alt.check!(value)
85
+ rescue ValidationError
86
+ end
87
+
88
+ raise ValidationError.new('expected one to match', '/any')
89
+ end
90
+ end
91
+
92
+ class Arr < Type::Core
93
+ class << self
94
+ def subname
95
+ 'arr'
96
+ end
97
+ end
98
+
99
+ @@allowed_param = { 'contents' => true, 'length' => true, 'type' => true }
100
+ def allowed_param?(p)
101
+ @@allowed_param[p]
102
+ end
103
+
104
+ def initialize(param, rx)
105
+ super
106
+
107
+ unless param['contents']
108
+ raise Rx::Exception, "no contents schema given for #{uri}"
109
+ end
110
+
111
+ @contents_schema = rx.make_schema(param['contents'])
112
+
113
+ if param['length']
114
+ @length_range = Rx::Helper::Range.new(param['length'])
115
+ end
116
+ end
117
+
118
+ def check!(value)
119
+ unless value.instance_of?(Array)
120
+ raise ValidationError.new("expected array got #{value.class}", '/arr')
121
+ end
122
+
123
+ if @length_range
124
+ unless @length_range.check(value.length)
125
+ raise ValidationError.new("expected array with #{@length_range} elements, got #{value.length}", '/arr')
126
+ end
127
+ end
128
+
129
+ if @contents_schema
130
+ value.each do |v|
131
+ @contents_schema.check!(v)
132
+ rescue ValidationError => e
133
+ e.path = '/arr' + e.path
134
+ raise e
135
+ end
136
+ end
137
+
138
+ true
139
+ end
140
+ end
141
+
142
+ class Bool < Type::Core
143
+ class << self
144
+ def subname
145
+ 'bool'
146
+ end
147
+ end
148
+
149
+ include Type::NoParams
150
+
151
+ def check!(value)
152
+ unless value.instance_of?(TrueClass) || value.instance_of?(FalseClass)
153
+ raise ValidationError.new("expected bool got #{value.inspect}", '/bool')
154
+ end
155
+ true
156
+ end
157
+ end
158
+
159
+ class Fail < Type::Core
160
+ class << self
161
+ def subname
162
+ 'fail'
163
+ end
164
+ end
165
+
166
+ include Type::NoParams
167
+
168
+ def check(_value)
169
+ false
170
+ end
171
+
172
+ def check!(_value)
173
+ raise ValidationError.new('explicit fail', '/fail')
174
+ end
175
+ end
176
+
177
+ class Date < Type::Core
178
+ class << self
179
+ def subname
180
+ 'date'
181
+ end
182
+ end
183
+
184
+ include Type::NoParams
185
+
186
+ def check!(value)
187
+ unless value.instance_of?(::Date)
188
+ raise ValidationError("expected Date got #{value.inspect}", '/date')
189
+ end
190
+ true
191
+ end
192
+ end
193
+
194
+ class Def < Type::Core
195
+ class << self
196
+ def subname
197
+ 'def'
198
+ end
199
+ end
200
+
201
+ include Type::NoParams
202
+ def check!(value)
203
+ raise ValidationError.new('def failed', '/def') if value.nil?
204
+ end
205
+ end
206
+
207
+ class Map < Type::Core
208
+ class << self
209
+ def subname
210
+ 'map'
211
+ end
212
+ end
213
+
214
+ @@allowed_param = { 'values' => true, 'type' => true }
215
+
216
+ def allowed_param?(p)
217
+ @@allowed_param[p]
218
+ end
219
+
220
+ def initialize(param, rx)
221
+ super
222
+
223
+ unless param['values']
224
+ raise Rx::Exception, "no values schema given for #{uri}"
225
+ end
226
+
227
+ @value_schema = rx.make_schema(param['values'])
228
+ end
229
+
230
+ def check!(value)
231
+ unless value.instance_of?(Hash) || (value.class.to_s == 'HashWithIndifferentAccess')
232
+ raise ValidationError.new("expected map got #{value.inspect}", '/map')
233
+ end
234
+
235
+ if @value_schema
236
+ value.each_value do |v|
237
+ @value_schema.check!(v)
238
+ rescue ValidationError => e
239
+ e.path = '/map' + e.path
240
+ raise e
241
+ end
242
+ end
243
+
244
+ true
245
+ end
246
+ end
247
+
248
+ class Nil < Type::Core
249
+ class << self
250
+ def subname
251
+ 'nil'
252
+ end
253
+ end
254
+
255
+ include Type::NoParams
256
+
257
+ def check!(value)
258
+ raise ValidationError.new("expected nil got #{value.inspect}", '/nil') unless value.nil?
259
+ true
260
+ end
261
+ end
262
+
263
+ class Num < Type::Core
264
+ class << self
265
+ def subname
266
+ 'num'
267
+ end
268
+ end
269
+
270
+ @@allowed_param = { 'range' => true, 'type' => true, 'value' => true }
271
+
272
+ def allowed_param?(p)
273
+ @@allowed_param[p]
274
+ end
275
+
276
+ def initialize(param, rx)
277
+ super
278
+
279
+ if param.key?('value')
280
+ unless param['value'].is_a?(Numeric)
281
+ raise Rx::Exception, "invalid value parameter for #{uri}"
282
+ end
283
+
284
+ @value = param['value']
285
+ end
286
+
287
+ @value_range = Rx::Helper::Range.new(param['range']) if param['range']
288
+ end
289
+
290
+ def check!(value)
291
+ unless value.is_a?(Numeric)
292
+ raise ValidationError.new("expected Numeric got #{value.inspect}", "/#{self.class.subname}")
293
+ end
294
+
295
+ if @value_range && !@value_range.check(value)
296
+ raise ValidationError.new("expected Numeric in range #{@value_range} got #{value.inspect}", "/#{self.class.subname}")
297
+ end
298
+
299
+ if @value && (value != @value)
300
+ raise ValidationError.new("expected Numeric to equal #{@value} got #{value.inspect}", "/#{self.class.subname}")
301
+ end
302
+ true
303
+ end
304
+ end
305
+
306
+ class Int < Type::Core::Num
307
+ class << self
308
+ def subname
309
+ 'int'
310
+ end
311
+ end
312
+
313
+ def initialize(param, rx)
314
+ super
315
+
316
+ if @value && (@value % 1 != 0)
317
+ raise Rx::Exception, "invalid value parameter for #{uri}"
318
+ end
319
+ end
320
+
321
+ def check!(value)
322
+ super
323
+ unless value % 1 == 0
324
+ raise ValidationError.new("expected Integer got #{value.inspect}", '/int')
325
+ end
326
+ true
327
+ end
328
+ end
329
+
330
+ class One < Type::Core
331
+ class << self
332
+ def subname
333
+ 'one'
334
+ end
335
+ end
336
+
337
+ include Type::NoParams
338
+
339
+ def check!(value)
340
+ unless [Numeric, String, TrueClass, FalseClass].any? { |cls| value.is_a?(cls) }
341
+ raise ValidationError.new("expected One got #{value.inspect}", '/one')
342
+ end
343
+ end
344
+ end
345
+
346
+ class Rec < Type::Core
347
+ class << self
348
+ def subname
349
+ 'rec'
350
+ end
351
+ end
352
+
353
+ @@allowed_param = {
354
+ 'type' => true,
355
+ 'rest' => true,
356
+ 'required' => true,
357
+ 'optional' => true
358
+ }
359
+
360
+ def allowed_param?(p)
361
+ @@allowed_param[p]
362
+ end
363
+
364
+ def initialize(param, rx)
365
+ super
366
+
367
+ @field = {}
368
+
369
+ @rest_schema = rx.make_schema(param['rest']) if param['rest']
370
+
371
+ %w[optional required].each do |type|
372
+ next unless param[type]
373
+ param[type].keys.each do |field|
374
+ if @field[field]
375
+ raise Rx::Exception, "#{field} in both required and optional"
376
+ end
377
+
378
+ @field[field] = {
379
+ required: (type == 'required'),
380
+ schema: rx.make_schema(param[type][field])
381
+ }
382
+ end
383
+ end
384
+ end
385
+
386
+ def check!(value)
387
+ unless value.instance_of?(Hash) || (value.class.to_s == 'HashWithIndifferentAccess')
388
+ raise ValidationError.new("expected Hash got #{value.class}", '/rec')
389
+ end
390
+
391
+ rest = []
392
+
393
+ value.each do |field, field_value|
394
+ unless @field[field]
395
+ rest.push(field)
396
+ next
397
+ end
398
+
399
+ begin
400
+ @field[field][:schema].check!(field_value)
401
+ rescue ValidationError => e
402
+ e.path = "/rec:'#{field}'"
403
+ raise e
404
+ end
405
+ end
406
+
407
+ @field.select { |k, _v| @field[k][:required] }.each do |pair|
408
+ unless value.key?(pair[0])
409
+ raise ValidationError.new("expected Hash to have key: '#{pair[0]}', only had #{value.keys.inspect}", '/rec')
410
+ end
411
+ end
412
+
413
+ unless rest.empty?
414
+ unless @rest_schema
415
+ raise ValidationError.new("Hash had extra keys: #{rest.inspect}", '/rec')
416
+ end
417
+ rest_hash = {}
418
+ rest.each { |field| rest_hash[field] = value[field] }
419
+ begin
420
+ @rest_schema.check!(rest_hash)
421
+ rescue ValidationError => e
422
+ e.path = '/rec'
423
+ raise e
424
+ end
425
+ end
426
+
427
+ true
428
+ end
429
+ end
430
+
431
+ class Seq < Type::Core
432
+ class << self; def subname
433
+ 'seq'
434
+ end; end
435
+ @@allowed_param = { 'tail' => true, 'contents' => true, 'type' => true }
436
+ def allowed_param?(p)
437
+ @@allowed_param[p]
438
+ end
439
+
440
+ def initialize(param, rx)
441
+ super
442
+
443
+ unless param['contents']&.is_a?(Array)
444
+ raise Rx::Exception, "missing or invalid contents for #{uri}"
445
+ end
446
+
447
+ @content_schemata = param['contents'].map { |s| rx.make_schema(s) }
448
+
449
+ @tail_schema = rx.make_schema(param['tail']) if param['tail']
450
+ end
451
+
452
+ def check!(value)
453
+ unless value.instance_of?(Array)
454
+ raise ValidationError.new("expected Array got #{value.inspect}", '/seq')
455
+ end
456
+ if value.length < @content_schemata.length
457
+ raise ValidationError.new("expected Array to have at least #{@content_schemata.length} elements, had #{value.length}", '/seq')
458
+ end
459
+ @content_schemata.each_index do |i|
460
+ @content_schemata[i].check!(value[i])
461
+ rescue ValidationError => e
462
+ e.path = '/seq' + e.path
463
+ raise e
464
+ end
465
+
466
+ if value.length > @content_schemata.length
467
+ unless @tail_schema
468
+ raise ValidationError.new('expected tail_schema', '/seq')
469
+ end
470
+ begin
471
+ @tail_schema.check!(value[
472
+ @content_schemata.length,
473
+ value.length - @content_schemata.length
474
+ ])
475
+ rescue ValidationError => e
476
+ e.path = '/seq' + e.path
477
+ raise e
478
+ end
479
+ end
480
+
481
+ true
482
+ end
483
+ end
484
+
485
+ class Str < Type::Core
486
+ class << self
487
+ def subname
488
+ 'str'
489
+ end
490
+ end
491
+
492
+ @@allowed_param = {
493
+ 'type' => true,
494
+ 'value' => true,
495
+ 'length' => true,
496
+ 'regex' => true
497
+ }
498
+
499
+ def allowed_param?(p)
500
+ @@allowed_param[p]
501
+ end
502
+
503
+ def initialize(param, rx)
504
+ super
505
+
506
+ if param['length']
507
+ @length_range = Rx::Helper::Range.new(param['length'])
508
+ end
509
+
510
+ if param.key?('value')
511
+ unless param['value'].instance_of?(String)
512
+ raise Rx::Exception, "invalid value parameter for #{uri}"
513
+ end
514
+
515
+ @value = param['value']
516
+ end
517
+
518
+ if param.key?('regex')
519
+ # boom do it here
520
+ end
521
+ end
522
+
523
+ def check!(value)
524
+ unless value.instance_of?(String)
525
+ raise ValidationError.new("expected String got #{value.inspect}", '/str')
526
+ end
527
+
528
+ if @length_range
529
+ unless @length_range.check(value.length)
530
+ raise ValidationError.new("expected string with #{@length_range} characters, got #{value.length}", '/str')
531
+ end
532
+ end
533
+
534
+ if @value && (value != @value)
535
+ raise ValidationError.new("expected #{@value.inspect} got #{value.inspect}", '/str')
536
+ end
537
+
538
+ true
539
+ end
540
+ end
541
+
542
+ class Time < Type::Core
543
+ class << self
544
+ def subname
545
+ 'time'
546
+ end
547
+ end
548
+
549
+ include Type::NoParams
550
+
551
+ def check!(value)
552
+ unless value.instance_of?(::Time)
553
+ raise ValidationError.new("expected Time got #{value.inspect}", '/time')
554
+ end
555
+ true
556
+ end
557
+ end
558
+
559
+ class << self
560
+ def core_types
561
+ [
562
+ Type::Core::All,
563
+ Type::Core::Any,
564
+ Type::Core::Arr,
565
+ Type::Core::Bool,
566
+ Type::Core::Date,
567
+ Type::Core::Def,
568
+ Type::Core::Fail,
569
+ Type::Core::Int,
570
+ Type::Core::Map,
571
+ Type::Core::Nil,
572
+ Type::Core::Num,
573
+ Type::Core::One,
574
+ Type::Core::Rec,
575
+ Type::Core::Seq,
576
+ Type::Core::Str,
577
+ Type::Core::Time
578
+ ]
579
+ end
580
+ end
581
+ end
582
+ end
583
+ end
@@ -0,0 +1,3 @@
1
+ module Rxrb
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,42 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "rxrb/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rxrb"
8
+ spec.version = Rxrb::VERSION
9
+ spec.authors = ["Omar Bohsali"]
10
+ spec.email = ["omar.bohsali@gmail.com"]
11
+
12
+ spec.summary = %q{Rx parser library}
13
+ spec.description = %q{Rx parser library, ported as a rubygem.}
14
+ spec.homepage = "https://github.com/omarish/rxrb"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
+
22
+ spec.metadata["homepage_uri"] = spec.homepage
23
+ # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
24
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
25
+ else
26
+ raise "RubyGems 2.0 or newer is required to protect against " \
27
+ "public gem pushes."
28
+ end
29
+
30
+ # Specify which files should be added to the gem when it is released.
31
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
33
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
+ end
35
+ spec.bindir = "exe"
36
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ["lib"]
38
+
39
+ spec.add_development_dependency "bundler", "~> 1.16"
40
+ spec.add_development_dependency "rake", "~> 10.0"
41
+ spec.add_development_dependency "rspec", "~> 3.2"
42
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rxrb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Omar Bohsali
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-11-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.2'
55
+ description: Rx parser library, ported as a rubygem.
56
+ email:
57
+ - omar.bohsali@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - ".travis.yml"
65
+ - CODE_OF_CONDUCT.md
66
+ - Gemfile
67
+ - Gemfile.lock
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - bin/console
72
+ - bin/setup
73
+ - lib/rxrb.rb
74
+ - lib/rxrb/rx.rb
75
+ - lib/rxrb/rx/helper.rb
76
+ - lib/rxrb/rx/type.rb
77
+ - lib/rxrb/rx/type/core.rb
78
+ - lib/rxrb/version.rb
79
+ - rxrb.gemspec
80
+ homepage: https://github.com/omarish/rxrb
81
+ licenses:
82
+ - MIT
83
+ metadata:
84
+ homepage_uri: https://github.com/omarish/rxrb
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.7.6
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Rx parser library
105
+ test_files: []