polyfill-data 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3fc564f62f95089c90ab7c84d558694513c676e2720e30a5587fda794b0446e2
4
+ data.tar.gz: 2466958db19b441691124b8085c60dbb16ad9522b257aa647bb5d816f6bb0b42
5
+ SHA512:
6
+ metadata.gz: '09a20ba5e0db01e1693fd27f63eafcd62e3cb6e7dbf49bc9f061e7bec5f9259f3cef29de156f5319791059ac152a169157dfbd4375b13e2f73f551511fb256b7'
7
+ data.tar.gz: 056fa220c31d080a4b3c3a68d606772bc8791495d42abcad66e80d59146568255d45a613411741223b82ddcc34ee5f3978099ed2aff79e4a9257d6720331dbff
checksums.yaml.gz.sig ADDED
Binary file
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # Polyfill - Data
2
+
3
+ Add the Ruby 3.2 Data class to earlier Rubies.
4
+
5
+ ## Installation
6
+
7
+ Install the gem and add to the application's Gemfile by executing:
8
+
9
+ $ bundle add polyfill-data
10
+
11
+ If bundler is not being used to manage dependencies, install the gem by executing:
12
+
13
+ $ gem install polyfill-data
14
+
15
+ Polyfill-Data is cryptographically signed. To be sure the gem you install hasn’t been tampered with:
16
+
17
+ Add my the key (if you haven’t already) as a trusted certificate
18
+
19
+ gem cert --add <(curl -Ls https://raw.github.com/saturnflyer/polyfill-data/main/certs/saturnflyer.pem)
20
+
21
+ gem install polyfill-data -P HighSecurity
22
+
23
+ ## Usage
24
+
25
+ ```ruby
26
+ require 'polyfill-data'
27
+
28
+ MyValue = Data.define(:some, :stuff)
29
+ a_value = MyValue.new(some: "thing", stuff: "here")
30
+ puts a_value.to_h # => { some: "thing", stuff: "here" }
31
+
32
+ another = a_value.with(stuff: "there")
33
+ puts another.eql?(a_value) # => false
34
+ puts another.to_h # => { some: "thing", stuff: "there" }
35
+ ```
36
+
37
+ ## Development
38
+
39
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
40
+
41
+ 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
42
+
43
+ ## Contributing
44
+
45
+ Bug reports and pull requests are welcome on GitHub at https://github.com/saturnflyer/polyfill-data.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/test_*.rb"]
10
+ end
11
+
12
+ task default: :test
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEPDCCAqSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAkMSIwIAYDVQQDDBlqaW0v
3
+ REM9c2F0dXJuZmx5ZXIvREM9Y29tMB4XDTIzMDExOTE1MTcwNloXDTI0MDExOTE1
4
+ MTcwNlowJDEiMCAGA1UEAwwZamltL0RDPXNhdHVybmZseWVyL0RDPWNvbTCCAaIw
5
+ DQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALujbiQtllLpXG8My8gDdiINTlT3
6
+ MVNwkagztozhLX/PWxekC1lBhCU9Eke2xRRcIZeK8CL/Hh984wN3H156J4b9yfUa
7
+ IoxKnItgCf2eDBJ0QMcaqgdfDdJp5km7+W0AdyOq5GuPGmGObPXReZWuB1FqS5z0
8
+ cRpoM/nOfYDI0T/obhBvcGt9mPibL4O5BnpJTj3X9NiMJ1KPv0zD0nlsEZy8iraY
9
+ P69pC/KykYIRM5hw4YYgFGjnftDFXoSdGRZ+wJn6Yb1MlJ4TMxRzSEZySZeSGlsk
10
+ tTVpGi3iftSJExvNWbilJqy73XtQHi846zCcqtVghwku3+0VbYr/0mygna4QzT/b
11
+ 2F4oW/1mu4aM/Phm+uyGcrmG2hioQqrZbOMGbi9Baa8xAob4HCUd1mfG+btjd61t
12
+ 5ckfDjqZLo0or9ATYU1F5G6kEJIjHiz5YgHxglcthQRHyWCa/r+M4DnpQ5TwBhhS
13
+ ZWoB5+W7KlfN1guDZ4LjDAUEsWCKsBNydM0XzQIDAQABo3kwdzAJBgNVHRMEAjAA
14
+ MAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUTNduUZSXfk8psUbclUtWl2qPf7MwHgYD
15
+ VR0RBBcwFYETamltQHNhdHVybmZseWVyLmNvbTAeBgNVHRIEFzAVgRNqaW1Ac2F0
16
+ dXJuZmx5ZXIuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQBpRBA0939h4raDJmIObTGj
17
+ T4ZgUdOs27GnQXKJOG50Z9o8sEuG3WDRPUBsck50PKmI6taNalaEVOeeLNXvbfl8
18
+ Fb17rZnhy/ssAUseVAojIPHxHvsgi1K76v5HJMzuM774ftDckjWVOBhJ85Jxyj9c
19
+ 1VZes12ut2udsSa2vE6niS3mxrCeKCjmPQ7M5a55/fMr2tVX9qgPYZJmK0ck/Weh
20
+ e0fZ+W4iiGTZSrfHqNe2BabhLeKQtowVBMvBKbhL7DwdkufDaOv77uN5nsSMZfzh
21
+ ebdplnosS17xWRZxj+T/Vob93PmQFd7AsRnaNu9HjesRTbiBxKus7I0CeLPAelpD
22
+ Nq/5JAtQf+uEeL5/QXF9Mwv44ERxVbTX0DcZYjaepSgpYQtOew9EXLqQj0mLSsxG
23
+ dxkiKqcX+yzo9RJLD9l/E1AWX125r1Fhiif4l6ehdl7Vllc3NQUOm1abdmHtCYjw
24
+ dG3yPWBWzzN4ovoBRqsuTJbF1wjkCjl5ex5KhfYbeDc=
25
+ -----END CERTIFICATE-----
data/lib/data.rb ADDED
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "polyfill/data/version"
4
+
5
+ if RUBY_VERSION >= "3.2.0"
6
+ warn "You can remove the 'polyfill-data' gem now."
7
+ else
8
+ Object.send(:remove_const, :Data) rescue nil
9
+ class Data < Object
10
+ class << self
11
+ undef_method :new
12
+ end
13
+
14
+ def self.define(*args, &block)
15
+ raise ArgumentError if args.any?(/=/)
16
+ klass = ::Class.new(self, &block)
17
+
18
+ klass.define_singleton_method(:members) { args.map{ _1.intern } }
19
+
20
+ klass.define_singleton_method(:new) do |*new_args, **new_kwargs, &block|
21
+ arg_comparison = new_kwargs.any? ? new_kwargs.keys : new_args
22
+ if arg_comparison.size != args.size
23
+ raise ArgumentError
24
+ end
25
+ self.allocate.tap do |instance|
26
+ args_to_hash = if !new_kwargs.any?
27
+ Hash[members.take(new_args.size).zip(new_args)]
28
+ else
29
+ new_kwargs
30
+ end
31
+ instance.send(:initialize, **args_to_hash, &block)
32
+ end
33
+ end
34
+
35
+ args.map do |arg|
36
+ if klass.method_defined?(arg)
37
+ raise ArgumentError, "duplicate member #{arg}"
38
+ end
39
+ klass.define_method(arg) do
40
+ @attributes[arg]
41
+ end
42
+ end
43
+
44
+ klass
45
+ end
46
+
47
+ def members
48
+ self.class.members
49
+ end
50
+
51
+ def initialize(*args, **kwargs)
52
+ @attributes = case
53
+ when args.empty? && kwargs.empty?
54
+ {}
55
+ when args.empty?
56
+ kwargs
57
+ else
58
+ raise ArgumentError unless args.length == members.length
59
+ Hash[members.zip(args)]
60
+ end
61
+ end
62
+
63
+ def deconstruct_keys(array)
64
+ raise TypeError unless array.is_a?(Array) || array.nil?
65
+ return @attributes if array&.first.nil?
66
+
67
+ @attributes.slice(*array)
68
+ end
69
+
70
+ def to_h(&block)
71
+ @attributes.to_h(&block)
72
+ end
73
+
74
+ def hash
75
+ to_h.hash
76
+ end
77
+
78
+ def eql?(other)
79
+ self.class == other.class && hash == other.hash
80
+ end
81
+
82
+ def ==(other)
83
+ self.class == other.class && to_h == other.to_h
84
+ end
85
+
86
+ def inspect
87
+ name = ["data", self.class.name].compact.join(" ")
88
+ attribute_markers = @attributes.map do |key, value|
89
+ insect_key = key.to_s.start_with?("@") ? ":#{key}" : key
90
+ "#{insect_key}=#{value}"
91
+ end
92
+ %(#<#{name} #{attribute_markers.join(" ")}>)
93
+ end
94
+
95
+ def with(**kwargs)
96
+ self.class.new(*@attributes.merge(kwargs).values)
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Polyfill
4
+ module Data
5
+ VERSION = "1.0.0"
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ require "data"
data/test/test_data.rb ADDED
@@ -0,0 +1,170 @@
1
+ # -*- coding: us-ascii -*-
2
+ # frozen_string_literal: false
3
+ require 'test_helper'
4
+
5
+ class TestData < Minitest::Test
6
+ def test_define
7
+ klass = Data.define(:foo, :bar)
8
+ assert_kind_of(Class, klass)
9
+ assert_equal(%i[foo bar], klass.members)
10
+
11
+ assert_raises(NoMethodError) { Data.new(:foo) }
12
+ assert_raises(TypeError) { Data.define(0) }
13
+
14
+ # Because some code is shared with Struct, check we don't share unnecessary functionality
15
+ assert_raises(TypeError) { Data.define(:foo, keyword_init: true) }
16
+ end
17
+
18
+ def test_define_edge_cases
19
+ # non-ascii
20
+ klass = Data.define(:"r\u{e9}sum\u{e9}")
21
+ o = klass.new(1)
22
+ assert_equal(1, o.send(:"r\u{e9}sum\u{e9}"))
23
+
24
+ # junk string
25
+ klass = Data.define(:"a\000")
26
+ o = klass.new(1)
27
+ assert_equal(1, o.send(:"a\000"))
28
+
29
+ # special characters in attribute names
30
+ klass = Data.define(:a, :b?)
31
+ x = Object.new
32
+ o = klass.new("test", x)
33
+ assert_same(x, o.b?)
34
+
35
+ klass = Data.define(:a, :b!)
36
+ x = Object.new
37
+ o = klass.new("test", x)
38
+ assert_same(x, o.b!)
39
+
40
+ assert_raises(ArgumentError) { Data.define(:x=) }
41
+ assert_raises(ArgumentError, /duplicate member/) { Data.define(:x, :x) }
42
+ end
43
+
44
+ def test_define_with_block
45
+ klass = Data.define(:a, :b) do
46
+ def c
47
+ a + b
48
+ end
49
+ end
50
+
51
+ assert_equal(3, klass.new(1, 2).c)
52
+ end
53
+
54
+ def test_initialize
55
+ klass = Data.define(:foo, :bar)
56
+
57
+ # Regular
58
+ test = klass.new(1, 2)
59
+ assert_equal(1, test.foo)
60
+ assert_equal(2, test.bar)
61
+ assert_equal(test, klass.new(1, 2))
62
+
63
+ # Keywords
64
+ test_kw = klass.new(foo: 1, bar: 2)
65
+ assert_equal(1, test_kw.foo)
66
+ assert_equal(2, test_kw.bar)
67
+ assert_equal(test_kw, klass.new(foo: 1, bar: 2))
68
+ assert_equal(test_kw, test)
69
+
70
+ # Wrong protocol
71
+ assert_raises(ArgumentError) { klass.new(1) }
72
+ assert_raises(ArgumentError) { klass.new(1, 2, 3) }
73
+ assert_raises(ArgumentError) { klass.new(foo: 1) }
74
+ assert_raises(ArgumentError) { klass.new(foo: 1, bar: 2, baz: 3) }
75
+ # Could be converted to foo: 1, bar: 2, but too smart is confusing
76
+ assert_raises(ArgumentError) { klass.new(1, bar: 2) }
77
+ end
78
+
79
+ def test_initialize_redefine
80
+ klass = Data.define(:foo, :bar) do
81
+ attr_reader :passed
82
+
83
+ def initialize(*args, **kwargs)
84
+ @passed = [args, kwargs]
85
+
86
+ super(foo: 1, bar: 2) # so we can experiment with passing wrong numbers of args
87
+ end
88
+ end
89
+ # require 'debug'; debugger
90
+ assert_equal([[], {foo: 1, bar: 2}], klass.new(foo: 1, bar: 2).passed)
91
+
92
+ # Positional arguments are converted to keyword ones
93
+ assert_equal([[], {foo: 1, bar: 2}], klass.new(1, 2).passed)
94
+
95
+ # Missing arguments can be fixed in initialize
96
+ assert_equal([[], {foo: 1}], klass.new(foo: 1).passed)
97
+
98
+ # Extra keyword arguments can be dropped in initialize
99
+ assert_equal([[], {foo: 1, bar: 2, baz: 3}], klass.new(foo: 1, bar: 2, baz: 3).passed)
100
+ end
101
+
102
+ def test_instance_behavior
103
+ klass = Data.define(:foo, :bar)
104
+
105
+ test = klass.new(1, 2)
106
+ assert_equal(1, test.foo)
107
+ assert_equal(2, test.bar)
108
+ assert_equal(%i[foo bar], test.members)
109
+ assert_equal(1, test.public_send(:foo))
110
+ assert_equal(0, test.method(:foo).arity)
111
+ assert_equal([], test.method(:foo).parameters)
112
+
113
+ assert_equal({foo: 1, bar: 2}, test.to_h)
114
+ assert_equal({"foo"=>"1", "bar"=>"2"}, test.to_h { [_1.to_s, _2.to_s] })
115
+
116
+ assert_equal({foo: 1, bar: 2}, test.deconstruct_keys(nil))
117
+ assert_equal({foo: 1}, test.deconstruct_keys(%i[foo]))
118
+ assert_equal({foo: 1}, test.deconstruct_keys(%i[foo baz]))
119
+ assert_raises(TypeError) { test.deconstruct_keys(0) }
120
+
121
+ assert_kind_of(Integer, test.hash)
122
+ end
123
+
124
+ def test_inspect
125
+ klass = Data.define(:a)
126
+ o = klass.new(1)
127
+ assert_equal("#<data a=1>", o.inspect)
128
+
129
+ Object.const_set(:Foo, klass)
130
+ assert_equal("#<data Foo a=1>", o.inspect)
131
+ Object.instance_eval { remove_const(:Foo) }
132
+
133
+ klass = Data.define(:@a)
134
+ o = klass.new(1)
135
+ assert_equal("#<data :@a=1>", o.inspect)
136
+ end
137
+
138
+ def test_equal
139
+ klass1 = Data.define(:a)
140
+ klass2 = Data.define(:a)
141
+ o1 = klass1.new(1)
142
+ o2 = klass1.new(1)
143
+ o3 = klass2.new(1)
144
+ assert_equal(o1, o2)
145
+ refute_equal(o1, o3)
146
+ end
147
+
148
+ def test_eql
149
+ klass1 = Data.define(:a)
150
+ klass2 = Data.define(:a)
151
+ o1 = klass1.new(1)
152
+ o2 = klass1.new(1)
153
+ o3 = klass2.new(1)
154
+ assert_operator(o1, :eql?, o2)
155
+ refute_operator(o1, :eql?, o3)
156
+ end
157
+
158
+ def test_memberless
159
+ klass = Data.define
160
+
161
+ test = klass.new
162
+
163
+ assert_equal(klass.new, test)
164
+ refute_equal(Data.define.new, test)
165
+
166
+ assert_equal('#<data >', test.inspect)
167
+ assert_equal([], test.members)
168
+ assert_equal({}, test.to_h)
169
+ end
170
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
4
+ require "data"
5
+ require "minitest/autorun"
data.tar.gz.sig ADDED
Binary file
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: polyfill-data
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jim Gay
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIEPDCCAqSgAwIBAgIBATANBgkqhkiG9w0BAQsFADAkMSIwIAYDVQQDDBlqaW0v
14
+ REM9c2F0dXJuZmx5ZXIvREM9Y29tMB4XDTIzMDExOTE1MTcwNloXDTI0MDExOTE1
15
+ MTcwNlowJDEiMCAGA1UEAwwZamltL0RDPXNhdHVybmZseWVyL0RDPWNvbTCCAaIw
16
+ DQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALujbiQtllLpXG8My8gDdiINTlT3
17
+ MVNwkagztozhLX/PWxekC1lBhCU9Eke2xRRcIZeK8CL/Hh984wN3H156J4b9yfUa
18
+ IoxKnItgCf2eDBJ0QMcaqgdfDdJp5km7+W0AdyOq5GuPGmGObPXReZWuB1FqS5z0
19
+ cRpoM/nOfYDI0T/obhBvcGt9mPibL4O5BnpJTj3X9NiMJ1KPv0zD0nlsEZy8iraY
20
+ P69pC/KykYIRM5hw4YYgFGjnftDFXoSdGRZ+wJn6Yb1MlJ4TMxRzSEZySZeSGlsk
21
+ tTVpGi3iftSJExvNWbilJqy73XtQHi846zCcqtVghwku3+0VbYr/0mygna4QzT/b
22
+ 2F4oW/1mu4aM/Phm+uyGcrmG2hioQqrZbOMGbi9Baa8xAob4HCUd1mfG+btjd61t
23
+ 5ckfDjqZLo0or9ATYU1F5G6kEJIjHiz5YgHxglcthQRHyWCa/r+M4DnpQ5TwBhhS
24
+ ZWoB5+W7KlfN1guDZ4LjDAUEsWCKsBNydM0XzQIDAQABo3kwdzAJBgNVHRMEAjAA
25
+ MAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUTNduUZSXfk8psUbclUtWl2qPf7MwHgYD
26
+ VR0RBBcwFYETamltQHNhdHVybmZseWVyLmNvbTAeBgNVHRIEFzAVgRNqaW1Ac2F0
27
+ dXJuZmx5ZXIuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQBpRBA0939h4raDJmIObTGj
28
+ T4ZgUdOs27GnQXKJOG50Z9o8sEuG3WDRPUBsck50PKmI6taNalaEVOeeLNXvbfl8
29
+ Fb17rZnhy/ssAUseVAojIPHxHvsgi1K76v5HJMzuM774ftDckjWVOBhJ85Jxyj9c
30
+ 1VZes12ut2udsSa2vE6niS3mxrCeKCjmPQ7M5a55/fMr2tVX9qgPYZJmK0ck/Weh
31
+ e0fZ+W4iiGTZSrfHqNe2BabhLeKQtowVBMvBKbhL7DwdkufDaOv77uN5nsSMZfzh
32
+ ebdplnosS17xWRZxj+T/Vob93PmQFd7AsRnaNu9HjesRTbiBxKus7I0CeLPAelpD
33
+ Nq/5JAtQf+uEeL5/QXF9Mwv44ERxVbTX0DcZYjaepSgpYQtOew9EXLqQj0mLSsxG
34
+ dxkiKqcX+yzo9RJLD9l/E1AWX125r1Fhiif4l6ehdl7Vllc3NQUOm1abdmHtCYjw
35
+ dG3yPWBWzzN4ovoBRqsuTJbF1wjkCjl5ex5KhfYbeDc=
36
+ -----END CERTIFICATE-----
37
+ date: 2023-01-19 00:00:00.000000000 Z
38
+ dependencies: []
39
+ description: Add the ruby 3.2 Data class to older rubies
40
+ email:
41
+ - jim@saturnflyer.com
42
+ executables: []
43
+ extensions: []
44
+ extra_rdoc_files: []
45
+ files:
46
+ - README.md
47
+ - Rakefile
48
+ - certs/saturnflyer.pem
49
+ - lib/data.rb
50
+ - lib/polyfill-data.rb
51
+ - lib/polyfill/data/version.rb
52
+ - test/test_data.rb
53
+ - test/test_helper.rb
54
+ homepage: https://github.com/saturnflyer/polyfill-data
55
+ licenses:
56
+ - MIT
57
+ metadata:
58
+ homepage_uri: https://github.com/saturnflyer/polyfill-data
59
+ source_code_uri: https://github.com/saturnflyer/polyfill-data.git
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 2.6.0
69
+ - - "<"
70
+ - !ruby/object:Gem::Version
71
+ version: 3.2.0
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubygems_version: 3.2.27
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: Add the ruby 3.2 Data class to older rubies
82
+ test_files:
83
+ - test/test_data.rb
84
+ - test/test_helper.rb
metadata.gz.sig ADDED
@@ -0,0 +1,3 @@
1
+
2
+ }d94@T'��ε\�,���Ӧ �;e����8F�x�K��*�����,� �++'qաt�ԝ�k �*,�㑩�Ci{&��H���8���ֱ7!#��R����ڎ˟M�A������.�p��뽏��c֭5�����D{C��[�l��D\��e��1>&�Z���^�:� !n�5�끼�V��8"�o�e��8mK�G*��F�l��� N�s��88:��c�'+"�ۊ�����Pt�,����<&��aV��A舀
3
+ [:�I{y%[���Vi@���v���8�e���������sw���^���