union 1.1.0 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: adbd1e81a50840bb72f6da5a8d8c8d4880f3cc13cf0a79c75244dbedf5efe28a
4
- data.tar.gz: 63daa94ff856cc50918633b19a4e97c6bf9ba57bebf1c531f4ade27feb138008
3
+ metadata.gz: 4078ed3374822297df80188098fb07eff8a7e6f7944d3b2b98dd473c2b93da41
4
+ data.tar.gz: 685ead99ae8858d415fbc20c54f17b2814b387b7619b9a529992724ada83bf0d
5
5
  SHA512:
6
- metadata.gz: 8948712b75415225ee8a97ffe6a54615245230f0efc2fa13dea7c4d2418a42ad253089476c44a7b9d7167e1fdb142cd6debc06dc2aaaa99f9cb6d096f1321ff0
7
- data.tar.gz: 7f2e18cc148c24eaf17b81549ccb04b6eb011a04c15963d5ce8d76c35effcd61c57281e31837da4348ee5545d5902a9bbf4f8835e0e036b79fdf35115768310b
6
+ metadata.gz: 5f8174f0ec82fee9e98d9a469bf9e46fd485b1702bbc0b574d14f00dcee6bcaf9dba42b9a274a46eb52a3a8f479c10be535cabf341c86f48ba565337a97b191a
7
+ data.tar.gz: 94ec356be18a6173be737683881e44ffb6696d6d66b1dab565c00e050cb089c2ce9648fbe0eedc154c57960fbe3a210dc5c1814ec43df43b2ae0f0b4dbbcace4
checksums.yaml.gz.sig CHANGED
Binary file
@@ -1,33 +1,41 @@
1
- == 1.1.0 - 24-Jun-2020
1
+ ## 1.3.0 - 18-Jul-2020
2
+ * Added two methods, which_member and current_value.
3
+ * Internal refactoring that also adds some stricter argument checking.
4
+
5
+ ## 1.2.0 - 24-Sep-2020
6
+ * Switched from test-unit to rspec.
7
+ * Added a Gemfile.
8
+
9
+ ## 1.1.0 - 24-Jun-2020
2
10
  * Switch to Apache-2.0 license, and add LICENSE file to repo.
3
11
 
4
- == 1.0.6 - 4-Nov-2018
12
+ ## 1.0.6 - 4-Nov-2018
5
13
  * The VERSION constant is now frozen.
6
14
  * Added some metadata to the gemspec.
7
15
  * Updated cert.
8
16
 
9
- == 1.0.5 - 5-Dec-2015
17
+ ## 1.0.5 - 5-Dec-2015
10
18
  * This gem is now signed.
11
19
  * Updated gemspec, adding a cert_chain and fixing the home page.
12
20
  * The gem related tasks now assume Rubygems 2.x.
13
21
 
14
- == 1.0.4 - 8-Oct-2014
22
+ ## 1.0.4 - 8-Oct-2014
15
23
  * Updated Rakefile for Rubygems 2.x.
16
24
  * Updated README and gemspec, removed Rubyforge references.
17
25
 
18
- == 1.0.3 - 22-Sep-2011
26
+ ## 1.0.3 - 22-Sep-2011
19
27
  * Refactored the Rakefile. Removed the old install task, added
20
28
  a default task, and reorganized the gem related tasks.
21
29
  * Minor fix/update for gemspec.
22
30
 
23
- == 1.0.2 - 3-Oct-2009
31
+ ## 1.0.2 - 3-Oct-2009
24
32
  * Some gemspec updates and one fix.
25
33
  * Added the :gem rake task.
26
34
 
27
- == 1.0.1 - 31-Jul-2009
35
+ ## 1.0.1 - 31-Jul-2009
28
36
  * Now compatible with Ruby 1.9.x
29
37
  * Changed the license to Artistic 2.0.
30
38
  * Some gemspec updates, including the addition of a license.
31
39
 
32
- == 1.0.0 - 10-Jun-2008
40
+ ## 1.0.0 - 10-Jun-2008
33
41
  * Initial release
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
@@ -1,9 +1,10 @@
1
- * CHANGES
1
+ * CHANGES.md
2
2
  * LICENSE
3
- * MANIFEST
4
- * README
3
+ * MANIFEST.md
4
+ * README.md
5
+ * Gemfile
5
6
  * Rakefile
6
7
  * union.gemspec
7
8
  * certs/djberg96_pub.pem
8
9
  * lib/union.rb
9
- * test/test_union.rb
10
+ * spec/union_spec.rb
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ [![Ruby](https://github.com/djberg96/union/actions/workflows/ruby.yml/badge.svg)](https://github.com/djberg96/union/actions/workflows/ruby.yml)
2
+
3
+ ## Description
4
+ The union library provides the Ruby analog of a C union.
5
+
6
+ ## Installation
7
+ `gem install union`
8
+
9
+ ## Adding the trusted cert
10
+ `gem cert --add <(curl -Ls https://raw.githubusercontent.com/djberg96/union/main/certs/djberg96_pub.pem)`
11
+
12
+ ## Synopsis
13
+ ```ruby
14
+ require 'union'
15
+
16
+ Union.new('Human', :name, :age, :height)
17
+ h = Union::Human.new
18
+
19
+ # Only one attribute of the union may be set
20
+ h.name = 'Daniel' # => #<struct Union::Human name="Daniel", age=nil>
21
+ h.age = 38 # => #<struct Union::Human name=nil, age=38>
22
+ ```
23
+
24
+ ## Known issues or bugs
25
+ None that I'm aware of. Please report any bugs you find on the project
26
+ page at on the github project page at https://github.com/djberg96/union.
27
+
28
+ ## License
29
+ Artistic-2.0
30
+
31
+ ## Copyright
32
+ (C) 2003-2021 Daniel J. Berger
33
+ All Rights Reserved.
34
+
35
+ ## Warranty
36
+ This package is provided "as is" and without any express or
37
+ implied warranties, including, without limitation, the implied
38
+ warranties of merchantability and fitness for a particular purpose.
39
+
40
+ ## Author
41
+ Daniel J. Berger
data/Rakefile CHANGED
@@ -1,16 +1,17 @@
1
1
  require 'rake'
2
2
  require 'rake/clean'
3
- require 'rake/testtask'
3
+ require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
4
5
 
5
- CLEAN.include("**/*.gem", "**/*.rbc", "**/*.rbx")
6
+ CLEAN.include("**/*.gem", "**/*.rbc", "**/*.rbx", "**/*.lock")
6
7
 
7
8
  namespace :gem do
8
9
  desc 'Build the union gem'
9
10
  task :create => [:clean] do
10
11
  require 'rubygems/package'
11
- spec = eval(IO.read('union.gemspec'))
12
+ spec = Gem::Specification.load('union.gemspec')
12
13
  spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem')
13
- Gem::Package.build(spec, true)
14
+ Gem::Package.build(spec)
14
15
  end
15
16
 
16
17
  task :install => [:create] do
@@ -19,9 +20,14 @@ namespace :gem do
19
20
  end
20
21
  end
21
22
 
22
- Rake::TestTask.new do |t|
23
- t.verbose = true
24
- t.warning = true
23
+ RuboCop::RakeTask.new
24
+
25
+ desc "Run the test suite"
26
+ RSpec::Core::RakeTask.new(:spec)
27
+
28
+ # Clean up afterwards
29
+ Rake::Task[:spec].enhance do
30
+ Rake::Task[:clean].invoke
25
31
  end
26
32
 
27
- task :default => :test
33
+ task :default => :spec
data/lib/union.rb CHANGED
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # The Union class provides an analogue of a C union. Only one member of
2
4
  # a Union object can be set to a non-nil value at a time.
3
5
  #
4
6
  class Union < Struct
5
7
  # The version of the union library
6
- VERSION = '1.1.0'.freeze
8
+ VERSION = '1.3.0'
7
9
 
8
10
  # Creates and returns a new Union. Unlike Struct::Class.new, this does not
9
11
  # take any arguments. You must assign attributes individually.
@@ -20,14 +22,7 @@ class Union < Struct
20
22
  #
21
23
  def initialize
22
24
  super
23
- members.each{ |attribute|
24
- m = %Q{
25
- def #{attribute}=(value)
26
- self['#{attribute}'] = value
27
- end
28
- }
29
- instance_eval(m)
30
- }
25
+ define_union_setters
31
26
  end
32
27
 
33
28
  # Identical to Struct attribute assignment, except that setting one instance
@@ -41,7 +36,55 @@ class Union < Struct
41
36
  # h[:age] = 38 # => #<struct Union::Human name=nil, age=38>
42
37
  #
43
38
  def []=(symbol, value)
39
+ # Validate that the symbol is a valid member
40
+ symbol_str = symbol.to_s
41
+ unless members.any? { |m| m.to_s == symbol_str }
42
+ raise ArgumentError, "no member '#{symbol}' in union"
43
+ end
44
+
45
+ # Set the value for the specified member
44
46
  super(symbol, value)
45
- members.each{ |m| super(m, nil) unless m.to_s == symbol.to_s }
47
+
48
+ # Clear all other members
49
+ members.each { |m| super(m, nil) unless m.to_s == symbol_str }
50
+
51
+ value
52
+ end
53
+
54
+ # Returns the name of the currently set member (the one with a non-nil value)
55
+ # Returns nil if no member is set
56
+ #
57
+ # Union.new('Human', :name, :age)
58
+ # h = Union::Human.new
59
+ # h.name = 'Daniel'
60
+ # h.which_member # => :name
61
+ #
62
+ def which_member
63
+ members.find { |member| !self[member].nil? }
64
+ end
65
+
66
+ # Returns the current value (the value of the non-nil member)
67
+ # Returns nil if no member is set
68
+ #
69
+ # Union.new('Human', :name, :age)
70
+ # h = Union::Human.new
71
+ # h.name = 'Daniel'
72
+ # h.current_value # => 'Daniel'
73
+ #
74
+ def current_value
75
+ member = which_member
76
+ member ? self[member] : nil
77
+ end
78
+
79
+ private
80
+
81
+ # Define setter methods for each union member using define_singleton_method
82
+ # This is safer and more efficient than instance_eval with string interpolation
83
+ def define_union_setters
84
+ members.each do |attribute|
85
+ define_singleton_method("#{attribute}=") do |value|
86
+ self[attribute] = value
87
+ end
88
+ end
46
89
  end
47
90
  end
@@ -0,0 +1,328 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'union'
4
+ require 'rspec'
5
+
6
+ RSpec.describe 'Union improvements' do
7
+ before(:all) do
8
+ Union.new('TestUnion', :name, :age, :height, :weight)
9
+ end
10
+
11
+ before do
12
+ @union = Union::TestUnion.new
13
+ end
14
+
15
+ describe '#which_member' do
16
+ context 'when no member is set' do
17
+ it 'returns nil' do
18
+ expect(@union.which_member).to be_nil
19
+ end
20
+ end
21
+
22
+ context 'when a member is set' do
23
+ it 'returns the symbol of the currently set member' do
24
+ @union.name = 'Alice'
25
+ expect(@union.which_member).to eq(:name)
26
+
27
+ @union.age = 30
28
+ expect(@union.which_member).to eq(:age)
29
+ end
30
+
31
+ it 'works with different data types' do
32
+ @union.height = 180.5
33
+ expect(@union.which_member).to eq(:height)
34
+
35
+ @union.weight = { value: 70, unit: 'kg' }
36
+ expect(@union.which_member).to eq(:weight)
37
+ end
38
+
39
+ it 'works when setting via string or symbol indexing' do
40
+ @union[:name] = 'Bob'
41
+ expect(@union.which_member).to eq(:name)
42
+
43
+ @union['age'] = 25
44
+ expect(@union.which_member).to eq(:age)
45
+ end
46
+ end
47
+
48
+ context 'when multiple members are set to nil explicitly' do
49
+ it 'returns nil' do
50
+ @union.name = 'Test'
51
+ @union.name = nil
52
+ expect(@union.which_member).to be_nil
53
+ end
54
+ end
55
+
56
+ context 'when false or empty values are set' do
57
+ it 'correctly identifies members with falsy but non-nil values' do
58
+ @union.name = false
59
+ expect(@union.which_member).to eq(:name)
60
+
61
+ @union.age = 0
62
+ expect(@union.which_member).to eq(:age)
63
+
64
+ @union.height = ''
65
+ expect(@union.which_member).to eq(:height)
66
+
67
+ @union.weight = []
68
+ expect(@union.which_member).to eq(:weight)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe '#current_value' do
74
+ context 'when no member is set' do
75
+ it 'returns nil' do
76
+ expect(@union.current_value).to be_nil
77
+ end
78
+ end
79
+
80
+ context 'when a member is set' do
81
+ it 'returns the value of the currently set member' do
82
+ @union.name = 'Bob'
83
+ expect(@union.current_value).to eq('Bob')
84
+
85
+ @union.height = 180.5
86
+ expect(@union.current_value).to eq(180.5)
87
+ end
88
+
89
+ it 'works with complex data types' do
90
+ complex_data = { name: 'John', details: [1, 2, 3] }
91
+ @union.weight = complex_data
92
+ expect(@union.current_value).to eq(complex_data)
93
+ end
94
+
95
+ it 'returns falsy but non-nil values correctly' do
96
+ @union.name = false
97
+ expect(@union.current_value).to eq(false)
98
+
99
+ @union.age = 0
100
+ expect(@union.current_value).to eq(0)
101
+
102
+ @union.height = ''
103
+ expect(@union.current_value).to eq('')
104
+ end
105
+ end
106
+
107
+ context 'consistency with which_member' do
108
+ it 'returns the value of the member returned by which_member' do
109
+ test_values = ['Alice', 42, 180.5, { test: 'data' }]
110
+ members = [:name, :age, :height, :weight]
111
+
112
+ test_values.zip(members).each do |value, member|
113
+ @union.send("#{member}=", value)
114
+ expect(@union.which_member).to eq(member)
115
+ expect(@union.current_value).to eq(value)
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ describe '#[]= enhanced error handling' do
122
+ context 'with invalid member names' do
123
+ it 'raises ArgumentError for symbol keys' do
124
+ expect { @union[:invalid] = 'test' }.to raise_error(ArgumentError, "no member 'invalid' in union")
125
+ expect { @union[:nonexistent] = 'test' }.to raise_error(ArgumentError, "no member 'nonexistent' in union")
126
+ end
127
+
128
+ it 'raises ArgumentError for string keys' do
129
+ expect { @union['invalid'] = 'test' }.to raise_error(ArgumentError, "no member 'invalid' in union")
130
+ expect { @union['nonexistent'] = 'test' }.to raise_error(ArgumentError, "no member 'nonexistent' in union")
131
+ end
132
+
133
+ it 'includes the invalid member name in the error message' do
134
+ expect { @union[:bad_key] = 'value' }.to raise_error(ArgumentError, /bad_key/)
135
+ expect { @union['another_bad_key'] = 'value' }.to raise_error(ArgumentError, /another_bad_key/)
136
+ end
137
+ end
138
+
139
+ context 'with valid member names' do
140
+ it 'accepts both string and symbol keys' do
141
+ expect { @union[:name] = 'Alice' }.not_to raise_error
142
+ expect { @union['age'] = 30 }.not_to raise_error
143
+ end
144
+
145
+ it 'treats string and symbol keys as equivalent' do
146
+ @union[:name] = 'Alice'
147
+ expect(@union['name']).to eq('Alice')
148
+
149
+ @union['age'] = 30
150
+ expect(@union[:age]).to eq(30)
151
+ end
152
+ end
153
+
154
+ context 'return value' do
155
+ it 'returns the assigned value' do
156
+ result = (@union[:name] = 'Charlie')
157
+ expect(result).to eq('Charlie')
158
+
159
+ result = (@union['age'] = 42)
160
+ expect(result).to eq(42)
161
+ end
162
+
163
+ it 'returns the assigned value even for falsy values' do
164
+ result = (@union[:name] = false)
165
+ expect(result).to eq(false)
166
+
167
+ result = (@union['age'] = 0)
168
+ expect(result).to eq(0)
169
+
170
+ result = (@union[:height] = nil)
171
+ expect(result).to be_nil
172
+ end
173
+ end
174
+ end
175
+
176
+ describe 'setter methods safety and functionality' do
177
+ context 'with various data types' do
178
+ it 'handles strings correctly' do
179
+ @union.name = 'String value'
180
+ expect(@union.name).to eq('String value')
181
+ expect(@union.age).to be_nil
182
+ expect(@union.height).to be_nil
183
+ expect(@union.weight).to be_nil
184
+ end
185
+
186
+ it 'handles numbers correctly' do
187
+ @union.age = 42
188
+ expect(@union.age).to eq(42)
189
+ expect(@union.name).to be_nil
190
+ expect(@union.height).to be_nil
191
+ expect(@union.weight).to be_nil
192
+ end
193
+
194
+ it 'handles arrays correctly' do
195
+ test_array = [1, 2, 3, 'test']
196
+ @union.height = test_array
197
+ expect(@union.height).to eq(test_array)
198
+ expect(@union.name).to be_nil
199
+ expect(@union.age).to be_nil
200
+ expect(@union.weight).to be_nil
201
+ end
202
+
203
+ it 'handles hashes correctly' do
204
+ test_hash = { key: 'value', nested: { data: 123 } }
205
+ @union.weight = test_hash
206
+ expect(@union.weight).to eq(test_hash)
207
+ expect(@union.name).to be_nil
208
+ expect(@union.age).to be_nil
209
+ expect(@union.height).to be_nil
210
+ end
211
+
212
+ it 'handles objects correctly' do
213
+ test_object = Object.new
214
+ @union.name = test_object
215
+ expect(@union.name).to eq(test_object)
216
+ expect(@union.age).to be_nil
217
+ end
218
+ end
219
+
220
+ context 'union behavior enforcement' do
221
+ it 'ensures only one member is set at a time via setters' do
222
+ @union.name = 'Alice'
223
+ @union.age = 30
224
+ @union.height = 170.5
225
+
226
+ # Only the last set member should have a value
227
+ expect(@union.name).to be_nil
228
+ expect(@union.age).to be_nil
229
+ expect(@union.height).to eq(170.5)
230
+ end
231
+
232
+ it 'ensures only one member is set at a time via []=' do
233
+ @union[:name] = 'Alice'
234
+ @union['age'] = 30
235
+ @union[:height] = 170.5
236
+
237
+ # Only the last set member should have a value
238
+ expect(@union[:name]).to be_nil
239
+ expect(@union['age']).to be_nil
240
+ expect(@union[:height]).to eq(170.5)
241
+ end
242
+
243
+ it 'works correctly when mixing setter methods and []=' do
244
+ @union.name = 'Alice'
245
+ @union[:age] = 30
246
+ @union['height'] = 170.5
247
+
248
+ expect(@union.name).to be_nil
249
+ expect(@union.age).to be_nil
250
+ expect(@union.height).to eq(170.5)
251
+ end
252
+ end
253
+ end
254
+
255
+ describe 'method definition safety' do
256
+ it 'uses define_singleton_method instead of instance_eval for security' do
257
+ # This test ensures that the setter methods are properly defined
258
+ # and work correctly without security vulnerabilities
259
+ expect(@union).to respond_to(:name=)
260
+ expect(@union).to respond_to(:age=)
261
+ expect(@union).to respond_to(:height=)
262
+ expect(@union).to respond_to(:weight=)
263
+
264
+ # Test that the methods work as expected
265
+ @union.name = 'Test'
266
+ expect(@union.name).to eq('Test')
267
+ end
268
+
269
+ it 'defines methods that properly delegate to []=' do
270
+ # Ensure that setter methods use the enhanced []= method
271
+ expect(@union).to receive(:[]=).with(:name, 'Test Value')
272
+ @union.name = 'Test Value'
273
+ end
274
+ end
275
+
276
+ describe 'edge cases and robustness' do
277
+ context 'with nil values' do
278
+ it 'allows explicitly setting members to nil' do
279
+ @union.name = 'Alice'
280
+ expect(@union.name).to eq('Alice')
281
+
282
+ @union.name = nil
283
+ expect(@union.name).to be_nil
284
+ expect(@union.which_member).to be_nil
285
+ expect(@union.current_value).to be_nil
286
+ end
287
+ end
288
+
289
+ context 'with empty collections' do
290
+ it 'treats empty arrays as valid values' do
291
+ @union.height = []
292
+ expect(@union.height).to eq([])
293
+ expect(@union.which_member).to eq(:height)
294
+ expect(@union.current_value).to eq([])
295
+ end
296
+
297
+ it 'treats empty hashes as valid values' do
298
+ @union.weight = {}
299
+ expect(@union.weight).to eq({})
300
+ expect(@union.which_member).to eq(:weight)
301
+ expect(@union.current_value).to eq({})
302
+ end
303
+
304
+ it 'treats empty strings as valid values' do
305
+ @union.name = ''
306
+ expect(@union.name).to eq('')
307
+ expect(@union.which_member).to eq(:name)
308
+ expect(@union.current_value).to eq('')
309
+ end
310
+ end
311
+
312
+ context 'with boolean values' do
313
+ it 'handles true values correctly' do
314
+ @union.name = true
315
+ expect(@union.name).to eq(true)
316
+ expect(@union.which_member).to eq(:name)
317
+ expect(@union.current_value).to eq(true)
318
+ end
319
+
320
+ it 'handles false values correctly' do
321
+ @union.name = false
322
+ expect(@union.name).to eq(false)
323
+ expect(@union.which_member).to eq(:name)
324
+ expect(@union.current_value).to eq(false)
325
+ end
326
+ end
327
+ end
328
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'union'
4
+ require 'rspec'
5
+
6
+ RSpec.describe Union do
7
+ before(:all) do
8
+ described_class.new('Human', :name, :age, :height)
9
+ end
10
+
11
+ before do
12
+ @union = Union::Human.new
13
+ end
14
+
15
+ example 'VERSION constant is set to expected value' do
16
+ expect(Union::VERSION).to eq('1.3.0')
17
+ expect(Union::VERSION).to be_frozen
18
+ end
19
+
20
+ example 'constructor does not accept arguments' do
21
+ expect{ Union::Human.new('Matz') }.to raise_error(ArgumentError)
22
+ end
23
+
24
+ example 'basic union attribute assignment functionality' do
25
+ expect{ @union.name = 'Daniel' }.not_to raise_error
26
+ expect(@union.name).to eq('Daniel')
27
+ end
28
+
29
+ example 'union attributes via method are set to expected value' do
30
+ expect{ @union.name = 'Daniel' }.not_to raise_error
31
+ expect{ @union.age = 38 }.not_to raise_error
32
+ expect(@union.name).to be_nil
33
+ expect(@union.height).to be_nil
34
+ expect(@union.age).to eq(38)
35
+ end
36
+
37
+ example 'union attributes via string ref are set to expected value' do
38
+ expect{ @union['name'] = 'Daniel' }.not_to raise_error
39
+ expect{ @union['age'] = 38 }.not_to raise_error
40
+ expect(@union['name']).to be_nil
41
+ expect(@union['height']).to be_nil
42
+ expect(@union['age']).to eq(38)
43
+ end
44
+
45
+ example 'union attributes via symbol ref are set to expected value' do
46
+ expect{ @union[:name] = 'Daniel' }.not_to raise_error
47
+ expect{ @union[:age] = 38 }.not_to raise_error
48
+ expect(@union[:name]).to be_nil
49
+ expect(@union[:height]).to be_nil
50
+ expect(@union[:age]).to eq(38)
51
+ end
52
+
53
+ example 'enhanced []= method returns assigned value' do
54
+ result = (@union[:name] = 'Test Value')
55
+ expect(result).to eq('Test Value')
56
+
57
+ result = (@union['age'] = 42)
58
+ expect(result).to eq(42)
59
+ end
60
+
61
+ example 'enhanced []= method validates member names' do
62
+ expect { @union[:invalid_member] = 'test' }.to raise_error(ArgumentError, /no member 'invalid_member' in union/)
63
+ expect { @union['another_invalid'] = 'test' }.to raise_error(ArgumentError, /no member 'another_invalid' in union/)
64
+ end
65
+
66
+ example 'setter methods are properly defined and work safely' do
67
+ # Test that all expected setter methods exist
68
+ expect(@union).to respond_to(:name=)
69
+ expect(@union).to respond_to(:age=)
70
+ expect(@union).to respond_to(:height=)
71
+
72
+ # Test that they work correctly
73
+ @union.name = 'Safe Test'
74
+ expect(@union.name).to eq('Safe Test')
75
+ expect(@union.age).to be_nil
76
+ expect(@union.height).to be_nil
77
+ end
78
+ end
data/union.gemspec CHANGED
@@ -2,26 +2,31 @@ require 'rubygems'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'union'
5
- spec.version = '1.1.0'
5
+ spec.version = '1.3.0'
6
6
  spec.author = 'Daniel J. Berger'
7
7
  spec.license = 'Apache-2.0'
8
8
  spec.email = 'djberg96@gmail.com'
9
9
  spec.homepage = 'https://github.com/djberg96/union'
10
10
  spec.summary = 'A struct-like C union for Ruby'
11
- spec.test_file = 'test/test_union.rb'
11
+ spec.test_file = 'spec/union_spec.rb'
12
12
  spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
13
13
  spec.cert_chain = Dir['certs/*']
14
14
 
15
- spec.extra_rdoc_files = ['README', 'CHANGES', 'MANIFEST']
16
15
  spec.add_development_dependency('rake')
16
+ spec.add_development_dependency('rspec', '~> 3.9')
17
+ spec.add_development_dependency('rubocop')
18
+ spec.add_development_dependency('rubocop-rspec')
17
19
 
18
20
  spec.metadata = {
19
- 'homepage_uri' => 'https://github.com/djberg96/union',
20
- 'bug_tracker_uri' => 'https://github.com/djberg96/union/issues',
21
- 'changelog_uri' => 'https://github.com/djberg96/union/blob/master/CHANGES',
22
- 'documentation_uri' => 'https://github.com/djberg96/union/wiki',
23
- 'source_code_uri' => 'https://github.com/djberg96/union',
24
- 'wiki_uri' => 'https://github.com/djberg96/union/wiki'
21
+ 'homepage_uri' => 'https://github.com/djberg96/union',
22
+ 'bug_tracker_uri' => 'https://github.com/djberg96/union/issues',
23
+ 'changelog_uri' => 'https://github.com/djberg96/union/blob/main/CHANGES.md',
24
+ 'documentation_uri' => 'https://github.com/djberg96/union/wiki',
25
+ 'source_code_uri' => 'https://github.com/djberg96/union',
26
+ 'wiki_uri' => 'https://github.com/djberg96/union/wiki',
27
+ 'rubygems_mfa_required' => 'true',
28
+ 'github_repo' => 'https://github.com/djberg96/union',
29
+ 'funding_uri' => 'https://github.com/sponsors/djberg96'
25
30
  }
26
31
 
27
32
  spec.description = <<-EOF
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: union
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - |
@@ -35,7 +35,7 @@ cert_chain:
35
35
  ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM
36
36
  WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh
37
37
  -----END CERTIFICATE-----
38
- date:
38
+ date: 2025-07-18 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: rake
@@ -51,6 +51,48 @@ dependencies:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rspec
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.9'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.9'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rubocop
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: rubocop-rspec
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
54
96
  description: |2
55
97
  The union library provides an analog to a C/C++ union for Ruby.
56
98
  In this implementation a union is a kind of struct where multiple
@@ -59,34 +101,33 @@ description: |2
59
101
  email: djberg96@gmail.com
60
102
  executables: []
61
103
  extensions: []
62
- extra_rdoc_files:
63
- - README
64
- - CHANGES
65
- - MANIFEST
104
+ extra_rdoc_files: []
66
105
  files:
106
+ - CHANGES.md
107
+ - Gemfile
67
108
  - LICENSE
68
- - test
69
- - test/test_union.rb
70
- - CHANGES
71
- - MANIFEST
72
- - union.gemspec
73
- - README
109
+ - MANIFEST.md
110
+ - README.md
74
111
  - Rakefile
75
- - certs
76
112
  - certs/djberg96_pub.pem
77
- - lib
78
113
  - lib/union.rb
114
+ - spec/union_improvements_spec.rb
115
+ - spec/union_spec.rb
116
+ - union.gemspec
79
117
  homepage: https://github.com/djberg96/union
80
118
  licenses:
81
119
  - Apache-2.0
82
120
  metadata:
83
121
  homepage_uri: https://github.com/djberg96/union
84
122
  bug_tracker_uri: https://github.com/djberg96/union/issues
85
- changelog_uri: https://github.com/djberg96/union/blob/master/CHANGES
123
+ changelog_uri: https://github.com/djberg96/union/blob/main/CHANGES.md
86
124
  documentation_uri: https://github.com/djberg96/union/wiki
87
125
  source_code_uri: https://github.com/djberg96/union
88
126
  wiki_uri: https://github.com/djberg96/union/wiki
89
- post_install_message:
127
+ rubygems_mfa_required: 'true'
128
+ github_repo: https://github.com/djberg96/union
129
+ funding_uri: https://github.com/sponsors/djberg96
130
+ post_install_message:
90
131
  rdoc_options: []
91
132
  require_paths:
92
133
  - lib
@@ -101,9 +142,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
142
  - !ruby/object:Gem::Version
102
143
  version: '0'
103
144
  requirements: []
104
- rubygems_version: 3.0.3
105
- signing_key:
145
+ rubygems_version: 3.5.22
146
+ signing_key:
106
147
  specification_version: 4
107
148
  summary: A struct-like C union for Ruby
108
149
  test_files:
109
- - test/test_union.rb
150
+ - spec/union_spec.rb
metadata.gz.sig CHANGED
Binary file
data/README DELETED
@@ -1,34 +0,0 @@
1
- = Description
2
- The union library provides the Ruby analog of a C union.
3
-
4
- = Installation
5
- gem install union
6
-
7
- = Synopsis
8
- require 'union'
9
-
10
- Union.new('Human', :name, :age, :height)
11
- h = Union::Human.new
12
-
13
- # Only one attribute of the union may be set
14
- h.name = 'Daniel' # => #<struct Union::Human name="Daniel", age=nil>
15
- h.age = 38 # => #<struct Union::Human name=nil, age=38>
16
-
17
- = Known issues or bugs
18
- None that I'm aware of. Please report any bugs you find on the project
19
- page at on the github project page at https://github.com/djberg96/union.
20
-
21
- = License
22
- Artistic 2.0
23
-
24
- = Copyright
25
- (C) 2003-2018 Daniel J. Berger
26
- All Rights Reserved.
27
-
28
- = Warranty
29
- This package is provided "as is" and without any express or
30
- implied warranties, including, without limitation, the implied
31
- warranties of merchantability and fitness for a particular purpose.
32
-
33
- = Author
34
- Daniel J. Berger
data/test/test_union.rb DELETED
@@ -1,51 +0,0 @@
1
- require 'union'
2
- require 'test/unit'
3
-
4
- class TC_Union < Test::Unit::TestCase
5
- def setup
6
- Union.new('Human', :name, :age, :height) unless defined? Union::Human
7
- @union = Union::Human.new
8
- end
9
-
10
- def test_union_version
11
- assert_equal('1.1.0', Union::VERSION)
12
- assert_true(Union::VERSION.frozen?)
13
- end
14
-
15
- def test_union_constructor
16
- assert_raise(ArgumentError){ Union::Human.new('Matz') }
17
- end
18
-
19
- def test_union_attribute_assignment_basic
20
- assert_nothing_raised{ @union.name = 'Daniel' }
21
- assert_equal('Daniel', @union.name)
22
- end
23
-
24
- def test_union_attribute_assignment_by_method_name
25
- assert_nothing_raised{ @union.name = 'Daniel' }
26
- assert_nothing_raised{ @union.age = 38 }
27
- assert_nil(@union.name)
28
- assert_nil(@union.height)
29
- assert_equal(38, @union.age)
30
- end
31
-
32
- def test_union_attribute_assignment_by_string_ref
33
- assert_nothing_raised{ @union['name'] = 'Daniel' }
34
- assert_nothing_raised{ @union['age'] = 38 }
35
- assert_nil(@union['name'])
36
- assert_nil(@union['height'])
37
- assert_equal(38, @union['age'])
38
- end
39
-
40
- def test_union_attribute_assignment_by_symbol_ref
41
- assert_nothing_raised{ @union[:name] = 'Daniel' }
42
- assert_nothing_raised{ @union[:age] = 38 }
43
- assert_nil(@union[:name])
44
- assert_nil(@union[:height])
45
- assert_equal(38, @union[:age])
46
- end
47
-
48
- def teardown
49
- @union = nil
50
- end
51
- end