astruct 2.11.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/astruct.rb +6 -81
- data/lib/astruct/behavior.rb +251 -0
- data/lib/astruct/version.rb +1 -2
- data/spec/lib/astruct/behavior_spec.rb +10 -0
- data/spec/lib/astruct/version_spec.rb +7 -0
- data/spec/lib/astruct_spec.rb +13 -0
- data/spec/spec_helper.rb +30 -0
- data/test/lib/{astruct_test.rb → astruct/test_behavior.rb} +13 -13
- data/test/test_helper.rb +2 -0
- metadata +91 -78
- data/.gitignore +0 -34
- data/.rvmrc +0 -49
- data/.travis.yml +0 -1
- data/Gemfile +0 -4
- data/Guardfile +0 -14
- data/LICENSE +0 -22
- data/README.md +0 -32
- data/Rakefile +0 -43
- data/astruct.gemspec +0 -23
- data/bench/add_more_vs_ostruct.rb +0 -34
- data/bench/delete_vs_ostruct.rb +0 -33
- data/bench/dump_vs_ostruct.rb +0 -33
- data/bench/dynamic_vs_ostruct.rb +0 -37
- data/bench/inspect_vs_ostruct.rb +0 -33
- data/bench/load_vs_ostruct.rb +0 -33
- data/bench/nested_vs_ostruct.rb +0 -37
- data/bench/new_vs_ostruct.rb +0 -31
- data/bench/some_updates_vs_ostruct.rb +0 -34
- data/lib/astruct/module.rb +0 -162
- data/test/helper.rb +0 -3
- data/test/lib/ostruct_test.rb +0 -227
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6990e238c22d0d907f210e88381630a930b20355
|
4
|
+
data.tar.gz: 028d8e80cc9b222c3383c511f514426a3d888eea
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 64a93ec3749af729bd2d2bce28a225f22ec46e8ad415e4ba8004f69ad82dd81a0cf9b925a6040b76fb316a4bbf6e954542bce07540503d5ce6f9a29289e418fd
|
7
|
+
data.tar.gz: 5708d234e2e1cea7f644dc7be147ebc267d3c931aacc5a93b7a4386a2cb588ed1949eb4acfaf0d360871843dbe1a0eefba09f4ba6d258fd897be26639ff43e67
|
data/lib/astruct.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative "astruct/behavior"
|
2
2
|
|
3
|
-
#
|
4
3
|
# = astruct.rb: AltStruct implementation
|
5
4
|
#
|
6
5
|
# Author:: Kurtis Rainbolt-Greene
|
@@ -10,85 +9,11 @@ require_relative 'astruct/module'
|
|
10
9
|
# create hash-like classes. Allowing you to create an object that can
|
11
10
|
# dynamically accept accessors and behaves very much like a Hash.
|
12
11
|
#
|
13
|
-
|
14
|
-
#
|
15
|
-
# An AltStruct is a data structure, similar to a Hash, that allows the
|
16
|
-
# definition of arbitrary attributes with their accompanying values. This is
|
17
|
-
# accomplished by using Ruby's metaprogramming to define methods on the class
|
18
|
-
# itself.
|
19
|
-
#
|
20
|
-
|
21
|
-
#
|
22
|
-
# == Examples:
|
23
|
-
#
|
24
|
-
# require 'astruct'
|
25
|
-
#
|
26
|
-
# class Profile < AltStruct
|
27
|
-
#
|
28
|
-
# end
|
29
|
-
#
|
30
|
-
# person = Profile.new name: "John Smith"
|
31
|
-
# person.age = 70
|
32
|
-
#
|
33
|
-
# puts person.name # => "John Smith"
|
34
|
-
# puts person.age # => 70
|
35
|
-
# puts person.dump # => { :name => "John Smith", :age => 70 }
|
36
|
-
#
|
37
|
-
|
38
|
-
#
|
39
|
-
# An AltStruct employs a Hash internally to store the methods and values and
|
40
|
-
# can even be initialized with one:
|
41
|
-
#
|
42
|
-
# australia = AltStruct.new country: "Australia", population: 20_000_000
|
43
|
-
# puts australia.inspect # => <AltStruct country="Australia", population=20000000>
|
44
|
-
#
|
45
|
-
|
46
|
-
#
|
47
|
-
# Hash keys with spaces or characters that would normally not be able to use for
|
48
|
-
# method calls (e.g. ()[]*) will not be immediately available on the
|
49
|
-
# AltStruct object as a method for retrieval or assignment, but can be still be
|
50
|
-
# reached through the Object#send method.
|
51
|
-
#
|
52
|
-
# measurements = AltStruct.new "length (in inches)" => 24
|
53
|
-
# measurements.send "length (in inches)" # => 24
|
54
|
-
#
|
55
|
-
# data_point = AltStruct.new :queued? => true
|
56
|
-
# data_point.queued? # => true
|
57
|
-
# data_point.send "queued?=", false
|
58
|
-
# data_point.queued? # => false
|
59
|
-
#
|
60
|
-
|
61
|
-
#
|
62
|
-
# Removing the presence of a method requires the execution the delete_field
|
63
|
-
# or delete (like a hash) method as setting the property value to +nil+
|
64
|
-
# will not remove the method.
|
65
|
-
#
|
66
|
-
# first_pet = AltStruct.new :name => 'Rowdy', :owner => 'John Smith'
|
67
|
-
# first_pet.owner = nil
|
68
|
-
# second_pet = AltStruct.new :name => 'Rowdy'
|
69
|
-
#
|
70
|
-
# first_pet == second_pet # -> false
|
71
|
-
#
|
72
|
-
# first_pet.delete_field(:owner)
|
73
|
-
# first_pet == second_pet # -> true
|
74
|
-
#
|
75
|
-
|
76
|
-
#
|
77
|
-
# == Implementation:
|
78
|
-
#
|
79
|
-
# An AltStruct utilizes Ruby's method lookup structure to and find and define
|
80
|
-
# the necessary methods for properties. This is accomplished through the method
|
81
|
-
# method_missing and define_method.
|
82
|
-
#
|
83
|
-
|
84
|
-
#
|
85
|
-
# This should be a consideration if there is a concern about the performance of
|
86
|
-
# the objects that are created, as there is much more overhead in the setting
|
87
|
-
# of these properties compared to using a Hash or a Struct.
|
88
|
-
#
|
89
12
|
class AltStruct
|
90
|
-
# We include all of the AltStruct::
|
13
|
+
# We include all of the AltStruct::Behavior Module in order to give AltStruct
|
91
14
|
# the same behavior as OpenStruct. It's better, however, to simply
|
92
|
-
# include AltStruct::
|
93
|
-
include AltStruct::
|
15
|
+
# include AltStruct::Behavior into your own class.
|
16
|
+
include AltStruct::Behavior
|
94
17
|
end
|
18
|
+
|
19
|
+
require_relative "astruct/version"
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
class AltStruct
|
4
|
+
# An AltStruct is a data structure, similar to a Hash, that allows the
|
5
|
+
# definition of arbitrary attributes with their accompanying values. This is
|
6
|
+
# accomplished by using Ruby's meta-programming to define methods on the
|
7
|
+
# class itself.
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# == Examples:
|
11
|
+
#
|
12
|
+
# require 'astruct'
|
13
|
+
#
|
14
|
+
# class Profile < AltStruct
|
15
|
+
#
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# person = Profile.new name: "John Smith"
|
19
|
+
# person.age = 70
|
20
|
+
#
|
21
|
+
# puts person.name # => "John Smith"
|
22
|
+
# puts person.age # => 70
|
23
|
+
# puts person.dump # => { :name => "John Smith", :age => 70 }
|
24
|
+
#
|
25
|
+
# An AltStruct employs a Hash internally to store the methods and values and
|
26
|
+
# can even be initialized with one:
|
27
|
+
#
|
28
|
+
# australia = AltStruct.new(
|
29
|
+
# country: "Australia",
|
30
|
+
# population: 20_000_000
|
31
|
+
# )
|
32
|
+
# puts australia.inspect
|
33
|
+
# # => <AltStruct country="Australia", population=20000000>
|
34
|
+
#
|
35
|
+
# Hash keys with spaces or characters that would normally not be able to use
|
36
|
+
# for method calls (e.g. ()[]*) will not be immediately available on the
|
37
|
+
# AltStruct object as a method for retrieval or assignment, but can be still
|
38
|
+
# be reached through the `Object#send` method.
|
39
|
+
#
|
40
|
+
# measurements = AltStruct.new "length (in inches)" => 24
|
41
|
+
# measurements.send "length (in inches)" # => 24
|
42
|
+
#
|
43
|
+
# data_point = AltStruct.new :queued? => true
|
44
|
+
# data_point.queued? # => true
|
45
|
+
# data_point.send "queued?=", false
|
46
|
+
# data_point.queued? # => false
|
47
|
+
#
|
48
|
+
# Removing the presence of a method requires the execution the delete_field
|
49
|
+
# or delete (like a hash) method as setting the property value to +nil+
|
50
|
+
# will not remove the method.
|
51
|
+
#
|
52
|
+
# first_pet = AltStruct.new :name => 'Rowdy', :owner => 'John Smith'
|
53
|
+
# first_pet.owner = nil
|
54
|
+
# second_pet = AltStruct.new :name => 'Rowdy'
|
55
|
+
#
|
56
|
+
# first_pet == second_pet # -> false
|
57
|
+
#
|
58
|
+
# first_pet.delete_field(:owner)
|
59
|
+
# first_pet == second_pet # -> true
|
60
|
+
#
|
61
|
+
#
|
62
|
+
# == Implementation:
|
63
|
+
#
|
64
|
+
# An AltStruct utilizes Ruby's method lookup structure to and find and define
|
65
|
+
# the necessary methods for properties. This is accomplished through the
|
66
|
+
# method `method_missing` and `define_singleton_method`.
|
67
|
+
#
|
68
|
+
# This should be a consideration if there is a concern about the performance
|
69
|
+
# of the objects that are created, as there is much more overhead in the
|
70
|
+
# setting of these properties compared to using a Hash or a Struct.
|
71
|
+
module Behavior
|
72
|
+
THREAD_KEY = :__as_ids__ # :nodoc:
|
73
|
+
NESTED_INSPECT = "...".freeze
|
74
|
+
INSPECT_DELIMITER = ", ".freeze
|
75
|
+
WRAP_PATTERN = /__/.freeze
|
76
|
+
UNSETABLE_PATTERN = /\@|\[|\]|\=\=|\~|\>|\<|\!\=/.freeze
|
77
|
+
SUFFIX_PATTERN = /(\?|\!)$/.freeze
|
78
|
+
|
79
|
+
# We want to give easy access to the table
|
80
|
+
attr_reader :table
|
81
|
+
|
82
|
+
# We want to automatically wrap important Ruby object methods
|
83
|
+
Object.instance_methods.each do |meth|
|
84
|
+
case meth
|
85
|
+
|
86
|
+
# Don't bother with already wrapped methods
|
87
|
+
when WRAP_PATTERN then next
|
88
|
+
|
89
|
+
# Skip methods that can't be set anyways
|
90
|
+
when UNSETABLE_PATTERN then next
|
91
|
+
|
92
|
+
# Get around Ruby's stupid method signature problems with ? and !
|
93
|
+
# suffixes
|
94
|
+
when SUFFIX_PATTERN then alias_method("__#{meth[0...-1]}__#{meth[-1]}".to_sym, meth)
|
95
|
+
|
96
|
+
# Finally, wrap regular methods
|
97
|
+
else alias_method("__#{meth}__".to_sym, meth)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Create a new field for each of the key/value pairs passed.
|
102
|
+
# By default the resulting OpenStruct object will have no
|
103
|
+
# attributes. If no pairs are passed avoid any work.
|
104
|
+
#
|
105
|
+
# require "astruct"
|
106
|
+
# hash = { "country" => "Australia", :population => 20_000_000 }
|
107
|
+
# data = AltStruct.new hash
|
108
|
+
#
|
109
|
+
# p data # => <AltStruct country="Australia" population=20000000>
|
110
|
+
#
|
111
|
+
# If you happen to be inheriting then you can define your own
|
112
|
+
# `@table` ivar before the `super()` call. AltStruct will respect
|
113
|
+
# your `@table`.
|
114
|
+
#
|
115
|
+
def initialize(pairs = {})
|
116
|
+
@table ||= {}
|
117
|
+
__iterate_set_over__(pairs) unless pairs.empty?
|
118
|
+
end
|
119
|
+
|
120
|
+
# This is the `load()` method, which works like initialize in that it
|
121
|
+
# will create new fields for each pair passed. It mimics the behavior of a
|
122
|
+
# Hash#merge.
|
123
|
+
def __load__(pairs)
|
124
|
+
__iterate_set_over__(pairs) unless pairs.empty?
|
125
|
+
end
|
126
|
+
alias_method :marshal_load, :__load__
|
127
|
+
alias_method :load, :__load__
|
128
|
+
alias_method :merge, :__load__
|
129
|
+
|
130
|
+
# This is the `load!()` method, which works like Hash#merge!
|
131
|
+
# See: `AltStruct#load()`
|
132
|
+
def __load__!(pairs)
|
133
|
+
__iterate_set_over__(pairs, true)
|
134
|
+
end
|
135
|
+
alias_method :marshal_load!, :__load__!
|
136
|
+
alias_method :load!, :__load__!
|
137
|
+
alias_method :merge!, :__load__!
|
138
|
+
|
139
|
+
# The `dump()` takes the table and out puts in it's natural hash
|
140
|
+
# format. In addition you can pass along a specific set of keys to
|
141
|
+
# dump.
|
142
|
+
def __dump__(*keys)
|
143
|
+
if keys.empty? then @table else __dump_specific__(keys) end
|
144
|
+
end
|
145
|
+
alias_method :marshal_dump, :__dump__
|
146
|
+
alias_method :dump, :__dump__
|
147
|
+
alias_method :to_hash, :__dump__
|
148
|
+
|
149
|
+
def __inspect__
|
150
|
+
"#<#{__class__}#{__dump_inspect__}>"
|
151
|
+
end
|
152
|
+
alias_method :inspect, :__inspect__
|
153
|
+
alias_method :to_sym, :__inspect__
|
154
|
+
|
155
|
+
# The `delete()` method removes a key/value pair on the @table
|
156
|
+
# and on the singleton class. It also mimics the Hash#delete method.
|
157
|
+
def __delete__(key)
|
158
|
+
__singleton_class__.send(:remove_method, key)
|
159
|
+
__singleton_class__.send(:remove_method, "#{key}=")
|
160
|
+
@table.delete(key.to_sym)
|
161
|
+
end
|
162
|
+
alias_method :delete_field, :__delete__
|
163
|
+
alias_method :delete, :__delete__
|
164
|
+
|
165
|
+
# The `method_missing()` method catches all non-tabled method calls.
|
166
|
+
# The AltStruct object will return two specific errors depending on
|
167
|
+
# the call.
|
168
|
+
def method_missing(method, *arguments)
|
169
|
+
name = method.to_s
|
170
|
+
if name.split("").last == "=" && arguments.size == 1
|
171
|
+
__define_field__(name.chomp!("="), arguments.first)
|
172
|
+
else
|
173
|
+
if name.split.last != "="
|
174
|
+
super
|
175
|
+
else arguments.size > 1
|
176
|
+
raise(ArgumentError,"wrong number of arguments (#{arguments.size} for 1)")
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def ==(other)
|
182
|
+
if other.respond_to?(:table)
|
183
|
+
table == other.table
|
184
|
+
else
|
185
|
+
false
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def freeze
|
190
|
+
super
|
191
|
+
@table.freeze
|
192
|
+
end
|
193
|
+
alias_method :__freeze__, :freeze
|
194
|
+
alias_method :__frozen?, :frozen?
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def __dump_inspect__
|
199
|
+
Thread.current[THREAD_KEY] ||= Set.new
|
200
|
+
|
201
|
+
if __dump__.any? then " #{__dump_subinspect__}" else "" end.tap do
|
202
|
+
__thread_ids__.delete(__object_id__)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def __dump_subinspect__
|
207
|
+
if __thread_ids__.add?(__object_id__)
|
208
|
+
__dump_string__.join(INSPECT_DELIMITER)
|
209
|
+
else
|
210
|
+
NESTED_INSPECT
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def __thread_ids__
|
215
|
+
Thread.current[THREAD_KEY]
|
216
|
+
end
|
217
|
+
|
218
|
+
def __define_field__(key, value)
|
219
|
+
__define_accessor__(key)
|
220
|
+
__set_table__(key, value)
|
221
|
+
end
|
222
|
+
|
223
|
+
def __define_accessor__(key)
|
224
|
+
singleton_class.send(:define_method, key) { @table[key] }
|
225
|
+
singleton_class.send(:define_method, "#{key}=") { |v| @table[key] = v }
|
226
|
+
end
|
227
|
+
|
228
|
+
def __set_table__(key, value)
|
229
|
+
@table.merge!(key => value) unless key.nil?
|
230
|
+
end
|
231
|
+
|
232
|
+
def __dump_specific__(keys)
|
233
|
+
@table.keep_if { |key| keys.include?(key.to_sym) }
|
234
|
+
end
|
235
|
+
|
236
|
+
def __dump_string__
|
237
|
+
__dump__.map { |key, value| "#{key}=#{value.inspect}" }
|
238
|
+
end
|
239
|
+
|
240
|
+
def __iterate_set_over__(pairs, force = false)
|
241
|
+
pairs.each do |key, value|
|
242
|
+
if force && respond_to?(key)
|
243
|
+
__set_table__(key, value)
|
244
|
+
else
|
245
|
+
__define_accessor__(key)
|
246
|
+
__set_table__(key, value)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
data/lib/astruct/version.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe AltStruct do
|
4
|
+
let(:astruct) { described_class.new }
|
5
|
+
|
6
|
+
it "should behave like AltStruct::Behavior" do
|
7
|
+
expect(astruct).to respond_to(*AltStruct::Behavior.instance_methods)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have aliases for standard methods" do
|
11
|
+
expect(astruct).to respond_to(:__object_id__)
|
12
|
+
end
|
13
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "codeclimate-test-reporter"
|
2
|
+
require "pry"
|
3
|
+
require "rspec"
|
4
|
+
require "astruct"
|
5
|
+
|
6
|
+
RSpec.configure do |let|
|
7
|
+
let.before("suite") do
|
8
|
+
CodeClimate::TestReporter.start
|
9
|
+
end
|
10
|
+
|
11
|
+
# Exit the spec after the first failure
|
12
|
+
let.fail_fast = true
|
13
|
+
|
14
|
+
# Only run a specific file, using the ENV variable
|
15
|
+
# Example: FILE=spec/blankgem/version_spec.rb bundle exec rake spec
|
16
|
+
let.pattern = ENV["FILE"]
|
17
|
+
|
18
|
+
# Show the slowest examples in the suite
|
19
|
+
let.profile_examples = true
|
20
|
+
|
21
|
+
# Colorize the output
|
22
|
+
let.color = true
|
23
|
+
|
24
|
+
# Output as a document string
|
25
|
+
let.default_formatter = "doc"
|
26
|
+
end
|
27
|
+
|
28
|
+
class ExampleAltStruct
|
29
|
+
include AltStruct::Behavior
|
30
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "test_helper"
|
2
|
+
require "minitest/autorun"
|
3
3
|
|
4
4
|
class TestAltStruct < MiniTest::Unit::TestCase
|
5
5
|
def setup
|
6
6
|
@empty = AltStruct.new
|
7
|
-
@example = AltStruct.new
|
7
|
+
@example = AltStruct.new(name: "Kurtis", age: 24)
|
8
8
|
end
|
9
9
|
|
10
10
|
def test_equality_with_two_empty_astructs
|
@@ -39,9 +39,9 @@ class TestAltStruct < MiniTest::Unit::TestCase
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def test_inspect_with_sub_struct_duplicate
|
42
|
-
@empty.
|
43
|
-
@empty.
|
44
|
-
expected =
|
42
|
+
@empty.substruct = AltStruct.new
|
43
|
+
@empty.substruct.subsubstruct = @empty
|
44
|
+
expected = "#<AltStruct substruct=#<AltStruct subsubstruct=#<AltStruct ...>>>"
|
45
45
|
actual = @empty.inspect
|
46
46
|
assert_equal expected, actual
|
47
47
|
end
|
@@ -50,7 +50,7 @@ class TestAltStruct < MiniTest::Unit::TestCase
|
|
50
50
|
@example.friends = AltStruct.new name: "Jason", age: 24
|
51
51
|
@example.friends.friends = AltStruct.new name: "John", age: 15
|
52
52
|
@example.friends.friends.friends = AltStruct.new name: "Ally", age: 32
|
53
|
-
expected =
|
53
|
+
expected = "#<AltStruct name=\"Kurtis\", age=24, friends=#<AltStruct name=\"Jason\", age=24, friends=#<AltStruct name=\"John\", age=15, friends=#<AltStruct name=\"Ally\", age=32>>>>"
|
54
54
|
actual = @example.inspect
|
55
55
|
assert_equal expected, actual
|
56
56
|
end
|
@@ -58,14 +58,14 @@ class TestAltStruct < MiniTest::Unit::TestCase
|
|
58
58
|
def test_inspect_with_twice_inspected_struct
|
59
59
|
@example.inspect
|
60
60
|
@example.inspect
|
61
|
-
expected =
|
61
|
+
expected = "#<AltStruct name=\"Kurtis\", age=24>"
|
62
62
|
actual = @example.inspect
|
63
63
|
assert_equal expected, actual
|
64
64
|
end
|
65
65
|
|
66
66
|
def test_inspect_with_empty_sub_struct
|
67
67
|
@empty.struct2 = AltStruct.new
|
68
|
-
expected =
|
68
|
+
expected = "#<AltStruct struct2=#<AltStruct>>"
|
69
69
|
actual = @empty.inspect
|
70
70
|
assert_equal expected, actual
|
71
71
|
end
|
@@ -91,7 +91,7 @@ class TestAltStruct < MiniTest::Unit::TestCase
|
|
91
91
|
# @example.freeze
|
92
92
|
# def @example.frozen?; nil end
|
93
93
|
# @example.freeze
|
94
|
-
# message =
|
94
|
+
# message = "[ruby-core:22559]"
|
95
95
|
# assert_raises(RuntimeError, message) { @example.name = "Jazzy" }
|
96
96
|
# # assert_raises(TypeError, message) { @example.name = "Jazzy" }
|
97
97
|
# end
|
@@ -105,13 +105,13 @@ class TestAltStruct < MiniTest::Unit::TestCase
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def test_delete_field_removes_getter_method
|
108
|
-
bug =
|
108
|
+
bug = "[ruby-core:33010]"
|
109
109
|
@example.delete_field :name
|
110
110
|
refute_respond_to @example, :name, bug
|
111
111
|
end
|
112
112
|
|
113
113
|
def test_delete_field_removes_setter_method
|
114
|
-
bug =
|
114
|
+
bug = "[ruby-core:33010]"
|
115
115
|
@example.delete_field :name
|
116
116
|
refute_respond_to @example, :name=, bug
|
117
117
|
end
|
@@ -130,7 +130,7 @@ class TestAltStruct < MiniTest::Unit::TestCase
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def test_method_missing_handles_square_bracket_equals
|
133
|
-
assert_raises(
|
133
|
+
assert_raises(NoMethodError) { @empty[:foo] = :bar }
|
134
134
|
end
|
135
135
|
|
136
136
|
def test_method_missing_handles_square_brackets
|