scoped_attr_accessor 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.
- data/.gitignore +17 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +127 -0
- data/Rakefile +10 -0
- data/lib/scoped_attr_accessor/include.rb +7 -0
- data/lib/scoped_attr_accessor/version.rb +3 -0
- data/lib/scoped_attr_accessor.rb +46 -0
- data/scoped_attr_accessor.gemspec +25 -0
- data/test/lib/test_scoped_attr_accessor.rb +17 -0
- data/test/lib/test_scoped_attr_accessor_include.rb +12 -0
- data/test/scoped_attr_accessor_test_module.rb +217 -0
- metadata +133 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm gemset use scoped_attr_accessor --create
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 David Brady
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# ScopedAttrAccessor
|
2
|
+
|
3
|
+
Adds scoped accessors to ruby. You can create writers, readers and
|
4
|
+
accessors in either private or protected scope. Does not affect the
|
5
|
+
scope of code that comes afterward. You can extend a single class (and
|
6
|
+
its subclasses) with scoped accessors, or you can extend ruby's entire
|
7
|
+
class hierarchy.
|
8
|
+
|
9
|
+
## Why Oh Why Does This Exist?!?
|
10
|
+
|
11
|
+
At the time of this writing (April 2013), the ruby community in
|
12
|
+
general is somewhat divided on the meaning of the concept of privacy
|
13
|
+
in ruby. For some, especially those who come from Java, C++, VB, or
|
14
|
+
some other language that enforces encapsulation with privacy, ruby's
|
15
|
+
ability to get around privacy means that encapsulation cannot be
|
16
|
+
enforced. Most of us (I count myself in this camp) have discarded the
|
17
|
+
use of privacy in ruby altogether, as if it were nothing more than a
|
18
|
+
half-hearted nod to other languages' encapsulation practices. Make
|
19
|
+
everything public, since everything's ultimately public anyway, we
|
20
|
+
say; using the private keyword is merely a speedbump which adds no
|
21
|
+
security but does add hassle and headache.
|
22
|
+
|
23
|
+
I am becoming more and more aware of a number of rubyists who consider
|
24
|
+
the use of private and protected methods in ruby to be a useful way to
|
25
|
+
communicate to the reader that the code is highly volatile, under
|
26
|
+
question, subject to change or outright removal, etc., and that for
|
27
|
+
these reasons the code should not be surfaced to the public API of the
|
28
|
+
class. They ALSO consider the private keyword to be merely a
|
29
|
+
speedbump, but one which communicates that maybe you should slow down
|
30
|
+
a bit before trying to access these portions of code. Furthermore,
|
31
|
+
making these methods private or protected makes them "exemplary" to
|
32
|
+
maintainers of the code, meaning that a maintainer will understand the
|
33
|
+
intent of the privacy, and be less likely to *accidentally* create an
|
34
|
+
external dependency on on a method that should have been kept private.
|
35
|
+
|
36
|
+
I am becoming more and more swayed by this second way of thinking, but
|
37
|
+
I find that it falls short in one key area: accessors. It is easy to
|
38
|
+
create a private method in ruby, but creating a private accessor
|
39
|
+
method is actually a bit tortuous. As a result, I see programmers who
|
40
|
+
strongly believe in using privacy to communicate undependable
|
41
|
+
interfaces frequently making use of either instance variables or
|
42
|
+
public accessors for their private variables. These variables are not
|
43
|
+
dependable, at least from a "stable interface" standpoint, so both
|
44
|
+
solutions offer an unfavorable tradeoff. While instance variables
|
45
|
+
communicate privacy, they force the object to depend on its own
|
46
|
+
undependable internal interface. Meanwhile, public accessors allow the
|
47
|
+
class to isolate itself from its undependable interface, but by making
|
48
|
+
it public the communication to the maintainer is that other classes
|
49
|
+
can and should depend on that undependable interface.
|
50
|
+
|
51
|
+
The reason programmers make this tradeoff is that there doesn't seem
|
52
|
+
to be an easy, clean, *elegant* way to create private and protected
|
53
|
+
accessors in ruby. My goal with this gem, then, is to create such a
|
54
|
+
way, so that those who wish to communicate "this variable is
|
55
|
+
undependable and it should be kept isolated for now" can do so easily.
|
56
|
+
|
57
|
+
## Installation
|
58
|
+
|
59
|
+
Add this line to your application's Gemfile:
|
60
|
+
|
61
|
+
gem 'scoped_attr_accessor'
|
62
|
+
|
63
|
+
And then execute:
|
64
|
+
|
65
|
+
$ bundle
|
66
|
+
|
67
|
+
Or install it yourself as:
|
68
|
+
|
69
|
+
$ gem install scoped_attr_accessor
|
70
|
+
|
71
|
+
## Usage
|
72
|
+
|
73
|
+
You can add scoped accessors to a single class (and its children) by
|
74
|
+
directly extending `ScopedAttrAccessor` in your class:
|
75
|
+
|
76
|
+
require 'scoped_attr_accessor'
|
77
|
+
|
78
|
+
class Primate
|
79
|
+
extend ScopedAttrAccessor
|
80
|
+
private_attr_accessor :some_weird_primate_only_counter
|
81
|
+
protected_attr_reader :some_weird_counter
|
82
|
+
end
|
83
|
+
|
84
|
+
class Monkey < Primate
|
85
|
+
# Monkey can define its own scoped accessors because Primate
|
86
|
+
# extended the module.
|
87
|
+
private_attr_reader :get_weird_monkey_only_stuff_here
|
88
|
+
private_attr_writer :put_weird_monkey_only_stuff_here
|
89
|
+
|
90
|
+
# use our inherited, protected reader
|
91
|
+
def sufficiently_weird?
|
92
|
+
some_weird_counter > 42
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
Alternately, if you require `scoped_attr_accessor/include`, ruby's
|
97
|
+
`Object` class will be extended with `ScopedAttrAccessor` making all
|
98
|
+
classes able to have protected and private accessors.
|
99
|
+
|
100
|
+
require 'scoped_attr_accessor/include'
|
101
|
+
|
102
|
+
class Primate
|
103
|
+
private_attr_accessor :private_primate_counter
|
104
|
+
end
|
105
|
+
|
106
|
+
## Avoid Dependency Infection
|
107
|
+
|
108
|
+
The '/include' form of this gem is a ruby-wide monkeypatch. Please
|
109
|
+
remember that it's perfectly fine to use it this way in your own
|
110
|
+
applications, but quite rude to use it this way in a library.
|
111
|
+
|
112
|
+
If you use scoped accessors in a gem or library of your own, please
|
113
|
+
consider using the non-include version, or, in Ruby 2.0, use
|
114
|
+
refinements to confine the include patch to your library.
|
115
|
+
|
116
|
+
## Ruby Versions
|
117
|
+
|
118
|
+
Tested to work on Ruby 1.9.3 and 2.0.
|
119
|
+
|
120
|
+
## Contributing
|
121
|
+
|
122
|
+
1. Fork it
|
123
|
+
1. Create your feature branch (`git checkout -b my-new-feature`)
|
124
|
+
1. Write tests for your feature or bug fix
|
125
|
+
1. Commit your changes (`git commit -am 'Add some feature'`)
|
126
|
+
1. Push to the branch (`git push origin my-new-feature`)
|
127
|
+
1. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# This module adds scoped accessor methods to a Ruby Class. For
|
4
|
+
# example:
|
5
|
+
#
|
6
|
+
# class Foo
|
7
|
+
# extend ScopedAttrAccessor
|
8
|
+
# private_attr_reader :thing1, :thing2, :thing3
|
9
|
+
# protected_attr_writer :counter
|
10
|
+
# protected_attr_accessor :flagbag
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# They work exactly the same as the regular ruby attr_accessor
|
14
|
+
# methods, except they are placed in the appropriate public or
|
15
|
+
# private scope as desired.
|
16
|
+
module ScopedAttrAccessor
|
17
|
+
def private_attr_reader(*names)
|
18
|
+
attr_reader(*names)
|
19
|
+
names.each {|name| private name}
|
20
|
+
end
|
21
|
+
|
22
|
+
def private_attr_writer(*names)
|
23
|
+
attr_writer(*names)
|
24
|
+
names.each {|name| private "#{name}=" }
|
25
|
+
end
|
26
|
+
|
27
|
+
def private_attr_accessor(*names)
|
28
|
+
attr_accessor(*names)
|
29
|
+
names.each {|name| private name; private "#{name}=" }
|
30
|
+
end
|
31
|
+
|
32
|
+
def protected_attr_reader(*names)
|
33
|
+
protected
|
34
|
+
attr_reader(*names)
|
35
|
+
end
|
36
|
+
|
37
|
+
def protected_attr_writer(*names)
|
38
|
+
protected
|
39
|
+
attr_writer(*names)
|
40
|
+
end
|
41
|
+
|
42
|
+
def protected_attr_accessor(*names)
|
43
|
+
protected
|
44
|
+
attr_accessor(*names)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'scoped_attr_accessor/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "scoped_attr_accessor"
|
8
|
+
spec.version = ScopedAttrAccessor::VERSION
|
9
|
+
spec.authors = ["David Brady"]
|
10
|
+
spec.email = ["dbrady@shinybit.com"]
|
11
|
+
spec.description = %q{Adds private_attr_reader, private_attr_writer, private_attr_accessor, protected_attr_reader, protected_attr_writer, protected_attr_accessor class macros}
|
12
|
+
spec.summary = %q{Adds private_* and protected_* attr_reader, attr_writer, and attr_accessor}
|
13
|
+
spec.homepage = "https://github.com/dbrady/scoped_attr_accessor.git"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "debugger", "~> 1.5"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "minitest", "~> 4.0"
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative '../../lib/scoped_attr_accessor'
|
3
|
+
|
4
|
+
# Directly extend Foo with ScopedAttrAccessor
|
5
|
+
module ScopedAttrAccessorTests
|
6
|
+
class Foo
|
7
|
+
extend ScopedAttrAccessor
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Load the common test suite
|
12
|
+
require_relative '../scoped_attr_accessor_test_module'
|
13
|
+
|
14
|
+
# Create a Test* class so it will run
|
15
|
+
class TestFoo < MiniTest::Unit::TestCase
|
16
|
+
include ScopedAttrAccessorTests
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'debugger'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
# Implicitly extend Foo with ScopedAttrAccessor by extending Object
|
4
|
+
require_relative '../../lib/scoped_attr_accessor/include'
|
5
|
+
|
6
|
+
# Load the common test suite
|
7
|
+
require_relative '../scoped_attr_accessor_test_module'
|
8
|
+
|
9
|
+
# Create a Test* class so it will run
|
10
|
+
class TestFooInclude < MiniTest::Unit::TestCase
|
11
|
+
include ScopedAttrAccessorTests
|
12
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
module ScopedAttrAccessorTests
|
2
|
+
# Foo uses all the accessor types, and also has a set of public
|
3
|
+
# attr_readers mixed in after the readers and another set after the
|
4
|
+
# writers and accessors. This is so the test suite can check to make
|
5
|
+
# sure that we stayed in public scope afterwards. A set of explicit
|
6
|
+
# poke and peek public accessor methods allow the test suite to modify
|
7
|
+
# and examine the contents of these private attributes.
|
8
|
+
class Foo
|
9
|
+
attr_reader :pub_read1, :pub_read2
|
10
|
+
private_attr_reader :priv_read1, :priv_read2
|
11
|
+
protected_attr_reader :prot_read1, :prot_read2
|
12
|
+
|
13
|
+
attr_reader :pub_read3, :pub_read4
|
14
|
+
|
15
|
+
private_attr_writer :priv_write1, :priv_write2
|
16
|
+
protected_attr_writer :prot_write1, :prot_write2
|
17
|
+
|
18
|
+
private_attr_accessor :priv_access1, :priv_access2
|
19
|
+
protected_attr_accessor :prot_access1, :prot_access2
|
20
|
+
|
21
|
+
attr_reader :pub_read5, :pub_read6
|
22
|
+
|
23
|
+
private
|
24
|
+
# this is a REALLY weird edge case, it's probably a bad idea to ever
|
25
|
+
# do this intentionally but I want to prove that, from this private
|
26
|
+
# scope, the prot_read3 accessor is created in protected scope AND
|
27
|
+
# that we bounce back not to public scope, but to private
|
28
|
+
protected_attr_reader :prot_read3
|
29
|
+
|
30
|
+
# We'll test this for privacy down below
|
31
|
+
attr_reader :priv_read3
|
32
|
+
|
33
|
+
public
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@pub_read1 = "pub_read1"
|
37
|
+
@pub_read2 = "pub_read2"
|
38
|
+
@pub_read3 = "pub_read3"
|
39
|
+
@pub_read4 = "pub_read4"
|
40
|
+
@pub_read5 = "pub_read5"
|
41
|
+
@pub_read6 = "pub_read6"
|
42
|
+
|
43
|
+
@prot_read1 = "prot_read1"
|
44
|
+
@prot_read2 = "prot_read2"
|
45
|
+
@prot_read3 = "prot_read3"
|
46
|
+
@prot_write1 = "prot_write1"
|
47
|
+
@prot_write2 = "prot_write2"
|
48
|
+
@prot_access1 = "prot_access1"
|
49
|
+
@prot_access2 = "prot_access2"
|
50
|
+
|
51
|
+
@priv_read1 = "priv_read1"
|
52
|
+
@priv_read2 = "priv_read2"
|
53
|
+
@priv_read3 = "priv_read3"
|
54
|
+
@priv_write1 = "priv_write1"
|
55
|
+
@priv_write2 = "priv_write2"
|
56
|
+
@priv_access1 = "priv_access1"
|
57
|
+
@priv_access2 = "priv_access2"
|
58
|
+
end
|
59
|
+
|
60
|
+
# Allow tests to peek and poke the private accessors
|
61
|
+
def peek_at_priv_read1; priv_read1; end
|
62
|
+
def peek_at_priv_read2; priv_read2; end
|
63
|
+
def peek_at_priv_read3; priv_read3; end
|
64
|
+
|
65
|
+
def peek_at_priv_write1; @priv_write1; end
|
66
|
+
def peek_at_priv_write2; @priv_write2; end
|
67
|
+
|
68
|
+
def peek_at_priv_access1; priv_access1; end
|
69
|
+
def peek_at_priv_access2; priv_access2; end
|
70
|
+
|
71
|
+
def poke_at_priv_write1(s); self.priv_write1 = s; end
|
72
|
+
def poke_at_priv_write2(s); self.priv_write2 = s; end
|
73
|
+
|
74
|
+
def poke_at_priv_access1(s); self.priv_access1 = s; end
|
75
|
+
def poke_at_priv_access2(s); self.priv_access2 = s; end
|
76
|
+
|
77
|
+
# Test only -- This method must not work!
|
78
|
+
def peek_at_priv_read3_via_protected_access_BAD; self.priv_read3; end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Bar inherits from Foo and is primarily here to test that protected
|
82
|
+
# members do in fact inherit correctly. There are no poke/peek methods
|
83
|
+
# in Foo for protected attributes, for example; we want to make sure
|
84
|
+
# the poke and peek--and their internal accessor calls--are defined
|
85
|
+
# here instead of up in Foo.
|
86
|
+
class Bar < Foo
|
87
|
+
def initialize
|
88
|
+
super
|
89
|
+
end
|
90
|
+
|
91
|
+
# peek at our inherited readers
|
92
|
+
def peek_at_prot_read1; prot_read1; end
|
93
|
+
def peek_at_prot_read2; prot_read2; end
|
94
|
+
def peek_at_prot_read3; prot_read3; end
|
95
|
+
|
96
|
+
# peek at the writers
|
97
|
+
def peek_at_prot_access1; prot_access1; end
|
98
|
+
def peek_at_prot_access2; prot_access2; end
|
99
|
+
def peek_at_prot_write1; @prot_write1; end
|
100
|
+
def peek_at_prot_write2; @prot_write2; end
|
101
|
+
|
102
|
+
def poke_at_prot_write1(s); self.prot_write1 = s; end
|
103
|
+
def poke_at_prot_write2(s); self.prot_write2 = s; end
|
104
|
+
|
105
|
+
def poke_at_prot_access1(s); self.prot_access1 = s; end
|
106
|
+
def poke_at_prot_access2(s); self.prot_access2 = s; end
|
107
|
+
end
|
108
|
+
|
109
|
+
def setup
|
110
|
+
@foo = Foo.new
|
111
|
+
@bar = Bar.new
|
112
|
+
end
|
113
|
+
|
114
|
+
# This is just a sanity check; if it fails start chewing the straps
|
115
|
+
def test_unaltered_public_accessors_still_work_normally
|
116
|
+
@foo.pub_read1.must_equal "pub_read1"
|
117
|
+
@foo.pub_read2.must_equal "pub_read2"
|
118
|
+
end
|
119
|
+
|
120
|
+
# Happy path test 1. If priv_read1-3 are private, they should be
|
121
|
+
# inaccessible
|
122
|
+
def test_private_readers_are_in_fact_private
|
123
|
+
lambda { @foo.priv_read1 }.must_raise NoMethodError
|
124
|
+
lambda { @foo.priv_read2 }.must_raise NoMethodError
|
125
|
+
lambda { @foo.priv_read3 }.must_raise NoMethodError
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_private_writers_are_in_fact_private
|
129
|
+
lambda { @foo.priv_write1 = "OH NOES" }.must_raise NoMethodError
|
130
|
+
lambda { @foo.priv_write2 = "OH NOES" }.must_raise NoMethodError
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_private_accessors_are_in_fact_private
|
134
|
+
lambda { @foo.priv_access1 = "OH NOES" }.must_raise NoMethodError
|
135
|
+
lambda { @foo.priv_access2 = "OH NOES" }.must_raise NoMethodError
|
136
|
+
end
|
137
|
+
|
138
|
+
# Happy path test 2. priv_read1 and priv_read2 may be inaccessible, but are they
|
139
|
+
# in fact present? Use the public peek_at_* methods to check them
|
140
|
+
def test_private_readers_do_in_fact_exist
|
141
|
+
@foo.peek_at_priv_read1.must_equal "priv_read1"
|
142
|
+
@foo.peek_at_priv_read2.must_equal "priv_read2"
|
143
|
+
@foo.peek_at_priv_read3.must_equal "priv_read3"
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_private_writers_do_in_fact_work_as_writers
|
147
|
+
@foo.poke_at_priv_write1 "OOH NEAT1"
|
148
|
+
@foo.poke_at_priv_write2 "OOH NEAT2"
|
149
|
+
@foo.peek_at_priv_write1.must_equal "OOH NEAT1"
|
150
|
+
@foo.peek_at_priv_write2.must_equal "OOH NEAT2"
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_private_accessors_do_in_fact_work_as_accessors
|
154
|
+
@foo.poke_at_priv_access1 "OOH WOW1"
|
155
|
+
@foo.poke_at_priv_access2 "OOH WOW2"
|
156
|
+
@foo.peek_at_priv_access1.must_equal "OOH WOW1"
|
157
|
+
@foo.peek_at_priv_access2.must_equal "OOH WOW2"
|
158
|
+
end
|
159
|
+
|
160
|
+
# Happy path test 3. If prot_read1-3 are protected, they should be
|
161
|
+
# inaccessible
|
162
|
+
def test_protected_readers_are_in_fact_private
|
163
|
+
lambda { @foo.prot_read1 }.must_raise NoMethodError
|
164
|
+
lambda { @foo.prot_read2 }.must_raise NoMethodError
|
165
|
+
lambda { @foo.prot_read3 }.must_raise NoMethodError
|
166
|
+
end
|
167
|
+
|
168
|
+
# Happy path test 4. prot_read1 and prot_read2 may be inaccessible, but are they
|
169
|
+
# in fact present? Use the public peek_at_* methods to check them
|
170
|
+
def test_protected_readers_do_in_fact_exist
|
171
|
+
@bar.peek_at_prot_read1.must_equal "prot_read1"
|
172
|
+
@bar.peek_at_prot_read2.must_equal "prot_read2"
|
173
|
+
@bar.peek_at_prot_read3.must_equal "prot_read3"
|
174
|
+
end
|
175
|
+
|
176
|
+
# And now the million dollar question: private_attr_accessor changes
|
177
|
+
# the scoping to private. When we come back out of this accessor, is
|
178
|
+
# Ruby still in private scope? Or does it revert to the scope it had
|
179
|
+
# beforehand?
|
180
|
+
def test_public_readers_AFTER_private_accessors_still_work_normally
|
181
|
+
@foo.pub_read3.must_equal "pub_read3"
|
182
|
+
@foo.pub_read4.must_equal "pub_read4"
|
183
|
+
@foo.pub_read5.must_equal "pub_read5"
|
184
|
+
@foo.pub_read6.must_equal "pub_read6"
|
185
|
+
end
|
186
|
+
|
187
|
+
# And the million-and-one-dollar question: Inside the explicitly
|
188
|
+
# private scope, after we created protected reader 3, did
|
189
|
+
# attr_accessor priv_read3 still get created privately?
|
190
|
+
def test_private_readers_AFTER_protected_accessors_are_STILL_private
|
191
|
+
lambda { @foo.peek_at_priv_read3_via_protected_access_BAD }.must_raise NoMethodError
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_protected_writers_are_in_fact_protected
|
195
|
+
lambda { @bar.prot_write1 = "OH NOES" }.must_raise NoMethodError
|
196
|
+
lambda { @bar.prot_write2 = "OH NOES" }.must_raise NoMethodError
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_protected_accessors_are_in_fact_protected
|
200
|
+
lambda { @bar.prot_access1 = "OH NOES" }.must_raise NoMethodError
|
201
|
+
lambda { @bar.prot_access2 = "OH NOES" }.must_raise NoMethodError
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_protected_writers_do_in_fact_work_as_writers
|
205
|
+
@bar.poke_at_prot_write1 "AWW YEAH1"
|
206
|
+
@bar.poke_at_prot_write2 "AWW YEAH2"
|
207
|
+
@bar.peek_at_prot_write1.must_equal "AWW YEAH1"
|
208
|
+
@bar.peek_at_prot_write2.must_equal "AWW YEAH2"
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_protected_accessors_do_in_fact_work_as_accessors
|
212
|
+
@bar.poke_at_prot_access1 "OH SNAP1"
|
213
|
+
@bar.poke_at_prot_access2 "OH SNAP2"
|
214
|
+
@bar.peek_at_prot_access1.must_equal "OH SNAP1"
|
215
|
+
@bar.peek_at_prot_access2.must_equal "OH SNAP2"
|
216
|
+
end
|
217
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: scoped_attr_accessor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Brady
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: debugger
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.5'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.5'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '4.0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '4.0'
|
78
|
+
description: Adds private_attr_reader, private_attr_writer, private_attr_accessor,
|
79
|
+
protected_attr_reader, protected_attr_writer, protected_attr_accessor class macros
|
80
|
+
email:
|
81
|
+
- dbrady@shinybit.com
|
82
|
+
executables: []
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- .rvmrc
|
88
|
+
- Gemfile
|
89
|
+
- LICENSE.txt
|
90
|
+
- README.md
|
91
|
+
- Rakefile
|
92
|
+
- lib/scoped_attr_accessor.rb
|
93
|
+
- lib/scoped_attr_accessor/include.rb
|
94
|
+
- lib/scoped_attr_accessor/version.rb
|
95
|
+
- scoped_attr_accessor.gemspec
|
96
|
+
- test/lib/test_scoped_attr_accessor.rb
|
97
|
+
- test/lib/test_scoped_attr_accessor_include.rb
|
98
|
+
- test/scoped_attr_accessor_test_module.rb
|
99
|
+
homepage: https://github.com/dbrady/scoped_attr_accessor.git
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
segments:
|
113
|
+
- 0
|
114
|
+
hash: 4018385502197385766
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
segments:
|
122
|
+
- 0
|
123
|
+
hash: 4018385502197385766
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 1.8.25
|
127
|
+
signing_key:
|
128
|
+
specification_version: 3
|
129
|
+
summary: Adds private_* and protected_* attr_reader, attr_writer, and attr_accessor
|
130
|
+
test_files:
|
131
|
+
- test/lib/test_scoped_attr_accessor.rb
|
132
|
+
- test/lib/test_scoped_attr_accessor_include.rb
|
133
|
+
- test/scoped_attr_accessor_test_module.rb
|