superclass_delegating_accessor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in superclass_delegating_accessor.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Akshay Vishnoi
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.
@@ -0,0 +1,76 @@
1
+ # SuperclassDelegatingAccessor
2
+
3
+ A Ruby utility that defines both class and instance accessors for class attributes. Creates private *_attr* and *_attr=* methods that can still be used if the public methods are overridden.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```shell
11
+ gem 'superclass_delegating_accessor', '~> 0.0.1'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ ```shell
17
+ $ bundle
18
+ ```
19
+
20
+ Or install it yourself as:
21
+
22
+ ```shell
23
+ $ gem install superclass_delegating_accessor
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ```ruby
29
+ class Person
30
+ superclass_delegating_accessor :hair_colors
31
+ end
32
+
33
+ Person.hair_colors = [:brown, :black, :blonde, :red]
34
+ Person.hair_colors # => [:brown, :black, :blonde, :red]
35
+ Person.new.hair_colors # => [:brown, :black, :blonde, :red]
36
+ ```
37
+
38
+ If a subclass changes the value then that would also change the value for parent class. Similarly if parent class changes the value then that would change the value of subclasses too.
39
+
40
+ ```ruby
41
+ class Male < Person
42
+ end
43
+
44
+ Male.hair_colors << :blue
45
+ Person.hair_colors # => [:brown, :black, :blonde, :red, :blue]
46
+ ```
47
+
48
+ To opt out of the instance reader method, pass `instance_reader: false`.
49
+
50
+ ```ruby
51
+ class Person
52
+ cattr_accessor :hair_colors, instance_writer: false, instance_reader: false
53
+ end
54
+
55
+ Person.new.hair_colors = [:brown] # => NoMethodError
56
+ Person.new.hair_colors # => NoMethodError
57
+ ```
58
+
59
+ Or pass `instance_accessor: false`, to opt out both instance methods.
60
+
61
+ ```ruby
62
+ class Person
63
+ cattr_accessor :hair_colors, instance_accessor: false
64
+ end
65
+
66
+ Person.new.hair_colors = [:brown] # => NoMethodError
67
+ Person.new.hair_colors # => NoMethodError
68
+ ```
69
+
70
+ ## Contributing
71
+
72
+ 1. Fork it
73
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
74
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
75
+ 4. Push to the branch (`git push origin my-new-feature`)
76
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ require "superclass_delegating_accessor/version"
2
+ require 'superclass_delegating_accessor/class'
3
+
4
+ module SuperclassDelegatingAccessor
5
+ end
@@ -0,0 +1 @@
1
+ require 'superclass_delegating_accessor/class/delegating_attributes'
@@ -0,0 +1,41 @@
1
+ require 'superclass_delegating_accessor/class/remove_method'
2
+
3
+ class Class
4
+ def superclass_delegating_accessor(name, options = {})
5
+ # Create private _name and _name= methods that can still be used if the public
6
+ # methods are overridden.
7
+ _superclass_delegating_accessor("_#{name}", options)
8
+
9
+ # Generate the public methods name, name=, and name?.
10
+ # These methods dispatch to the private _name, and _name= methods, making them
11
+ # overridable.
12
+ singleton_class.send(:define_method, name) { send("_#{name}") }
13
+ singleton_class.send(:define_method, "#{name}?") { !!send("_#{name}") }
14
+ singleton_class.send(:define_method, "#{name}=") { |value| send("_#{name}=", value) }
15
+
16
+ # If an instance_reader is needed, generate public instance methods name and name?.
17
+ if options[:instance_reader] != false
18
+ define_method(name) { send("_#{name}") }
19
+ define_method("#{name}?") { !!send("#{name}") }
20
+ end
21
+ end
22
+
23
+ private
24
+ # Take the object being set and store it in a method. This gives us automatic
25
+ # inheritance behavior, without having to store the object in an instance
26
+ # variable and look up the superclass chain manually.
27
+ def _stash_object_in_method(object, method, instance_reader = true)
28
+ singleton_class.remove_possible_method!(method)
29
+ singleton_class.send(:define_method, method) { object }
30
+ remove_possible_method!(method)
31
+ define_method(method) { object } if instance_reader
32
+ end
33
+
34
+ def _superclass_delegating_accessor(name, options = {})
35
+ singleton_class.send(:define_method, "#{name}=") do |value|
36
+ _stash_object_in_method(value, name, options[:instance_reader] != false)
37
+ end
38
+ send("#{name}=", nil)
39
+ singleton_class.send(:private, name, "#{name}=")
40
+ end
41
+ end
@@ -0,0 +1,7 @@
1
+ class Module
2
+ def remove_possible_method!(method)
3
+ if method_defined?(method) || private_method_defined?(method)
4
+ undef_method(method)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module SuperclassDelegatingAccessor
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'superclass_delegating_accessor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "superclass_delegating_accessor"
8
+ spec.version = SuperclassDelegatingAccessor::VERSION
9
+ spec.authors = ["Akshay Vishnoi"]
10
+ spec.email = ["akshay.vishnoi@yahoo.com"]
11
+ spec.description = 'A Ruby utility that defines both class and instance accessors for class attributes. Creates private *_attr* and *_attr=* methods that can still be used if the public methods are overridden.'
12
+ spec.summary = 'A Ruby utility that defines both class and instance accessors for class attributes. Creates private *_attr* and *_attr=* methods that can still be used if the public methods are overridden.'
13
+ spec.homepage = 'https://github.com/akshay-vishnoi/superclass_delegating_accessor'
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 "rake"
23
+ spec.add_development_dependency "minitest", "~> 5.3.1"
24
+ end
@@ -0,0 +1,119 @@
1
+ lib = File.expand_path('../../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'minitest/autorun'
5
+ require 'superclass_delegating_accessor'
6
+
7
+ module DelegatingFixtures
8
+ class Parent
9
+ end
10
+
11
+ class Child < Parent
12
+ superclass_delegating_accessor :some_attribute
13
+ end
14
+
15
+ class Mokopuna < Child
16
+ end
17
+
18
+ class PercysMom
19
+ superclass_delegating_accessor :superpower
20
+ end
21
+
22
+ class Percy < PercysMom
23
+ end
24
+ end
25
+
26
+ class DelegatingAttributesTest < ::Minitest::Test
27
+ Assertion = Minitest::Assertion
28
+ include DelegatingFixtures
29
+ attr_reader :single_class, :single_class_instance
30
+
31
+ def setup
32
+ @single_class = Class.new(Object)
33
+ @single_class_instance = @single_class.new
34
+ end
35
+
36
+ def test_simple_accessor_declaration
37
+ single_class.superclass_delegating_accessor :both
38
+
39
+ # `single_class` should have private accessor methods
40
+ assert single_class.private_methods.include?(:_both)
41
+ assert single_class.private_methods.include?(:_both=)
42
+
43
+ # `single_class` should have public accessor methods
44
+ assert single_class.public_methods.include?(:both)
45
+ assert single_class.public_methods.include?(:both=)
46
+ assert single_class.public_methods.include?(:both?)
47
+
48
+ # `single_class` should have public instance methods
49
+ assert single_class_instance.public_methods.include?(:both)
50
+ assert single_class_instance.public_methods.include?(:both?)
51
+ end
52
+
53
+ def test_simple_accessor_declaration_with_instance_reader_false
54
+ single_class.superclass_delegating_accessor :no_instance_reader, instance_reader: false
55
+
56
+ # `single_class` should have private accessor methods
57
+ assert single_class.private_methods.include?(:_no_instance_reader)
58
+ assert single_class.private_methods.include?(:_no_instance_reader=)
59
+
60
+ # `single_class` should have public accessor methods
61
+ assert single_class.public_methods.include?(:no_instance_reader)
62
+ assert single_class.public_methods.include?(:no_instance_reader=)
63
+ assert single_class.public_methods.include?(:no_instance_reader?)
64
+
65
+ # `single_class` should not have public instance methods
66
+ assert !single_class_instance.public_methods.include?(:no_instance_reader)
67
+ assert !single_class_instance.public_methods.include?(:no_instance_reader?)
68
+ end
69
+
70
+ def test_working_with_simple_attributes
71
+ single_class.superclass_delegating_accessor :both
72
+
73
+ single_class.both = "HMMM"
74
+
75
+ assert_equal "HMMM", single_class.both
76
+ assert_equal true, single_class.both?
77
+
78
+ assert_equal "HMMM", single_class.new.both
79
+ assert_equal true, single_class.new.both?
80
+
81
+ single_class.both = false
82
+ assert_equal false, single_class.both?
83
+ end
84
+
85
+ def test_child_class_delegates_to_parent_but_can_be_overridden
86
+ parent = Class.new
87
+ parent.superclass_delegating_accessor :both
88
+ child = Class.new(parent)
89
+ parent.both = "1"
90
+ assert_equal "1", child.both
91
+
92
+ child.both = "2"
93
+ assert_equal "1", parent.both
94
+ assert_equal "2", child.both
95
+
96
+ parent.both = "3"
97
+ assert_equal "3", parent.both
98
+ assert_equal "2", child.both
99
+ end
100
+
101
+ def test_delegation_stops_at_the_right_level
102
+ assert_nil Percy.superpower
103
+ assert_nil PercysMom.superpower
104
+
105
+ PercysMom.superpower = :heatvision
106
+ assert_equal :heatvision, Percy.superpower
107
+ end
108
+
109
+ def test_delegation_stops_for_nil
110
+ Mokopuna.some_attribute = nil
111
+ Child.some_attribute = "1"
112
+
113
+ assert_equal "1", Child.some_attribute
114
+ assert_nil Mokopuna.some_attribute
115
+ ensure
116
+ Child.some_attribute = nil
117
+ end
118
+
119
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: superclass_delegating_accessor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Akshay Vishnoi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-03-19 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: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
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: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: minitest
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 5.3.1
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: 5.3.1
62
+ description: A Ruby utility that defines both class and instance accessors for class
63
+ attributes. Creates private *_attr* and *_attr=* methods that can still be used
64
+ if the public methods are overridden.
65
+ email:
66
+ - akshay.vishnoi@yahoo.com
67
+ executables: []
68
+ extensions: []
69
+ extra_rdoc_files: []
70
+ files:
71
+ - .gitignore
72
+ - Gemfile
73
+ - LICENSE.txt
74
+ - README.md
75
+ - Rakefile
76
+ - lib/superclass_delegating_accessor.rb
77
+ - lib/superclass_delegating_accessor/class.rb
78
+ - lib/superclass_delegating_accessor/class/delegating_attributes.rb
79
+ - lib/superclass_delegating_accessor/class/remove_method.rb
80
+ - lib/superclass_delegating_accessor/version.rb
81
+ - superclass_delegating_accessor.gemspec
82
+ - test/delegating_attributes_test.rb
83
+ homepage: https://github.com/akshay-vishnoi/superclass_delegating_accessor
84
+ licenses:
85
+ - MIT
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 1.8.25
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: A Ruby utility that defines both class and instance accessors for class attributes.
108
+ Creates private *_attr* and *_attr=* methods that can still be used if the public
109
+ methods are overridden.
110
+ test_files:
111
+ - test/delegating_attributes_test.rb