typed_struct 0.1.0 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +32 -7
- data/lib/typed_struct/version.rb +1 -1
- data/lib/typed_struct.rb +38 -18
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b49cf9fe619f10d5b29cd5a25cb5ad6b881c05db4a8de195235a471182e8a93
|
4
|
+
data.tar.gz: d90fbe0ae7d7886208207e12dbd71c99b07238a453fce26469fdef534f7210b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ee1d309ac25b3b76e03b5acf485c1d7ac6159aaf74adbad3e72db771a153679bfa0a08569f3957df7489cf221bfdd1f11fc0c648c065496cba74bffa7fa15e0
|
7
|
+
data.tar.gz: c30d9b77718eb33435ec5b5995c078db3cf1a99e0d456c1a45f26b06bac57bbc14d255adc070a965b81df7aafb6edd9d0074fd74851c828d1681685a1d375e61
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
typed_struct (0.1.
|
4
|
+
typed_struct (0.1.4)
|
5
5
|
rbs (~> 1.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -9,7 +9,7 @@ GEM
|
|
9
9
|
specs:
|
10
10
|
diff-lcs (1.4.4)
|
11
11
|
rake (13.0.3)
|
12
|
-
rbs (1.
|
12
|
+
rbs (1.5.1)
|
13
13
|
rspec (3.10.0)
|
14
14
|
rspec-core (~> 3.10.0)
|
15
15
|
rspec-expectations (~> 3.10.0)
|
data/README.md
CHANGED
@@ -1,8 +1,37 @@
|
|
1
1
|
# TypedStruct
|
2
2
|
|
3
|
-
|
3
|
+
A Typed Struct is a lightweight data structure inspired by [Dry Struct](https://github.com/dry-rb/dry-struct), which allows for reading and writing properties while making use of a flexible and powerful type checking system, which also incorporates Ruby's [RBS](https://github.com/ruby/rbs/) for type definitions.
|
4
4
|
|
5
|
-
|
5
|
+
## Example
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require 'typed_struct' # unless using rails
|
9
|
+
|
10
|
+
User = TypedStruct.new name: String, # an instance of String
|
11
|
+
age: Integer, # an instance of Integer
|
12
|
+
username: /\w{4,}/, # must match given Regexp
|
13
|
+
rating: (0..5), # must be value from 0 to 5
|
14
|
+
type: "User", # must by a string with value "User"
|
15
|
+
interests: Rbs("Array[String]"), # an RBS generic type (an Array of Strings)
|
16
|
+
preferences: Rbs("{ opt_out_of_emails: bool, additional: untyped }") # RBS record type
|
17
|
+
|
18
|
+
clive = User.new name: "Clive",
|
19
|
+
age: 22,
|
20
|
+
interests: %w[surfing skiing],
|
21
|
+
preferences: { opt_out_of_emails: true, additional: { preferred_theme: :dark } },
|
22
|
+
type: "User",
|
23
|
+
rating: 4,
|
24
|
+
username: "cliveabc"
|
25
|
+
|
26
|
+
clive.age # 22
|
27
|
+
clive.age = '22' # => Error
|
28
|
+
clive.preferences = { "opt_out_of_emails" => true, "additional" => nil } # error - type mismatch, not Symbol keys
|
29
|
+
clive.freeze # no more changes can be made
|
30
|
+
```
|
31
|
+
|
32
|
+
Note that a `TypedStruct` inherits from `Struct` directly, so anything from `Struct` is also available in `TypedStruct` - see [Struct docs](https://ruby-doc.org/core-3.0.1/Struct.html) for more info.
|
33
|
+
|
34
|
+
**See [RBS reference](https://github.com/ruby/rbs/blob/3c046c77c3006211a1a14eedc35221ac4198f788/docs/syntax.md) for more info on writing RBS types**
|
6
35
|
|
7
36
|
## Installation
|
8
37
|
|
@@ -20,10 +49,6 @@ Or install it yourself as:
|
|
20
49
|
|
21
50
|
$ gem install typed_struct
|
22
51
|
|
23
|
-
## Usage
|
24
|
-
|
25
|
-
TODO: Write usage instructions here
|
26
|
-
|
27
52
|
## Development
|
28
53
|
|
29
54
|
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,7 +57,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
57
|
|
33
58
|
## Contributing
|
34
59
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
60
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/johansenja/typed_struct.
|
36
61
|
|
37
62
|
## License
|
38
63
|
|
data/lib/typed_struct/version.rb
CHANGED
data/lib/typed_struct.rb
CHANGED
@@ -4,11 +4,27 @@ require_relative "typed_struct/version"
|
|
4
4
|
require_relative "typed_struct/type_checking"
|
5
5
|
require "rbs"
|
6
6
|
|
7
|
+
def Rbs(type_str)
|
8
|
+
RBS::Parser.parse_type(type_str)
|
9
|
+
end
|
10
|
+
|
7
11
|
class TypedStruct < Struct
|
8
12
|
include TypeChecking
|
9
13
|
|
14
|
+
OVERRIDING_NATIVE_METHOD_MSG =
|
15
|
+
"*** WARNING *** property %s overrides a native method in #{name}. Consider using something else (called from %s)".freeze
|
16
|
+
|
17
|
+
# any methods which are able to be overridden
|
18
|
+
alias_method :__class__, :class
|
19
|
+
|
10
20
|
class << self
|
11
|
-
def new(**properties)
|
21
|
+
def new(opts = Options.new, **properties)
|
22
|
+
properties.each_key do |prop|
|
23
|
+
if method_defined?(prop)
|
24
|
+
$stdout.puts OVERRIDING_NATIVE_METHOD_MSG % [prop.inspect, caller(3).first]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
12
28
|
super(*properties.keys, keyword_init: true).tap do |klass|
|
13
29
|
klass.class.instance_eval do
|
14
30
|
include TypeChecking
|
@@ -16,15 +32,20 @@ class TypedStruct < Struct
|
|
16
32
|
end
|
17
33
|
|
18
34
|
klass.instance_eval do
|
19
|
-
@options = { types: properties }
|
35
|
+
@options = { types: properties, options: opts }
|
36
|
+
|
37
|
+
define_method :[]= do |key, val|
|
38
|
+
prop = properties[key]
|
39
|
+
unless val_is_type? val, prop
|
40
|
+
raise "Unexpected type #{val.class} for #{key.inspect} (expected #{prop})"
|
41
|
+
end
|
42
|
+
|
43
|
+
super key, val
|
44
|
+
end
|
45
|
+
|
20
46
|
properties.each_key do |k|
|
21
47
|
define_method :"#{k}=" do |val|
|
22
|
-
|
23
|
-
if val_is_type? val, prop
|
24
|
-
raise "Unexpected type #{val.class} for #{k.inspect} (expected #{prop})"
|
25
|
-
end
|
26
|
-
# it seems that structs behave in such a way that you can't call super here, but it
|
27
|
-
# will still set the value anyway
|
48
|
+
self[k] = val
|
28
49
|
end
|
29
50
|
end
|
30
51
|
end
|
@@ -33,18 +54,17 @@ class TypedStruct < Struct
|
|
33
54
|
end
|
34
55
|
|
35
56
|
def initialize(**attrs)
|
36
|
-
opts = self.
|
37
|
-
opts[:types].
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
57
|
+
opts = self.__class__.options
|
58
|
+
vals = opts[:types].to_h do |prop, expected_type|
|
59
|
+
value = attrs.fetch(prop, opts[:options][:default])
|
60
|
+
unless val_is_type? value, expected_type
|
61
|
+
raise "Unexpected type #{value.class} for #{prop.inspect} (expected #{expected_type})"
|
62
|
+
end
|
63
|
+
[prop, value]
|
42
64
|
end
|
43
65
|
|
44
|
-
super
|
66
|
+
super **vals
|
45
67
|
end
|
46
|
-
end
|
47
68
|
|
48
|
-
|
49
|
-
RBS::Parser.parse_type(type_str)
|
69
|
+
Options = TypedStruct.new({ default: nil }, default: Rbs("untyped"))
|
50
70
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: typed_struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joseph Johansen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbs
|