internal 0.1.0alpha01
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 +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/design_rationale.md +9 -0
- data/internal.gemspec +26 -0
- data/lib/internal/version.rb +37 -0
- data/lib/internal.rb +86 -0
- data/test/internal_test.rb +67 -0
- metadata +141 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create use "ruby-1.9.3-p392@internal"
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Daniel da Silva Ferreira (dsferreira)
|
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,29 @@
|
|
1
|
+
# Internal
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'internal'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install internal
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/design_rationale.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# First Attempt
|
2
|
+
|
3
|
+
This attempt is based on the following concepts:
|
4
|
+
|
5
|
+
1. Create module Internal to extend a given class 'Foo'
|
6
|
+
2. Use protected to define the internal interface
|
7
|
+
3. Use binding_of_caller gem to udpate the methods visibility
|
8
|
+
|
9
|
+
## NOTE: Abandoned since we couldn't get a solution for class methods
|
data/internal.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'internal/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'internal'
|
8
|
+
spec.version = Internal::VERSION
|
9
|
+
spec.authors = ['Daniel da Silva Ferreira (dsferreira)']
|
10
|
+
spec.email = ['danieldasilvaferreira@gmail.com']
|
11
|
+
spec.description = %q{Internal}
|
12
|
+
spec.summary = %q{Makes a class, module or method internal}
|
13
|
+
spec.homepage = ''
|
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_dependency 'sender'
|
22
|
+
spec.add_dependency 'binding_of_caller'
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'minitest'
|
26
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Internal
|
2
|
+
def self.version
|
3
|
+
critical = 0 # Broken backwards compatibility of public interface
|
4
|
+
# Production code based on previous releases maybe be broken by this release
|
5
|
+
major = 1 # Changed public interface. No backwards compatibility issues.
|
6
|
+
# Production code based on previous releases should not present any issues after upgrade.
|
7
|
+
# Production code based on this release may be broken when using previous releases.
|
8
|
+
minor = 0 # Changed internal interface
|
9
|
+
# There should be no impact on third party software
|
10
|
+
# Library extensions using library internal interface may be broken.
|
11
|
+
patch = nil # Changed private interface (protected and/or private methods). Bug fixes. Refactoring.
|
12
|
+
# Patch needs to increase for each commit. Patch is a three digits figure.
|
13
|
+
# No side effects of any sort should be detected
|
14
|
+
alpha = 1 # First phase of development of new major or critical release
|
15
|
+
beta = nil # release candidate for first critical release (v0.9.0, v1.0.0.0beta1, v1.0.0)
|
16
|
+
pre_release = nil # release candidate of new minor releases
|
17
|
+
release_candidate = nil # Used before releasing new major or critical releases
|
18
|
+
|
19
|
+
version = "#{critical}.#{major}.#{minor}"
|
20
|
+
|
21
|
+
if patch
|
22
|
+
version += ".#{'%03d' % patch}"
|
23
|
+
elsif pre_release
|
24
|
+
version += "pre#{'%02d' % pre_release}"
|
25
|
+
elsif release_candidate
|
26
|
+
version += "rc#{release_candidate}"
|
27
|
+
elsif alpha
|
28
|
+
version += "alpha#{'%02d' % alpha}"
|
29
|
+
elsif beta
|
30
|
+
version += "beta#{beta}"
|
31
|
+
end
|
32
|
+
version
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
VERSION = version
|
37
|
+
end
|
data/lib/internal.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'internal/version'
|
2
|
+
require 'binding_of_caller'
|
3
|
+
|
4
|
+
module Internal
|
5
|
+
def caller_internal?
|
6
|
+
caller_namespace_root == class_namespace_root
|
7
|
+
end
|
8
|
+
private :caller_internal?
|
9
|
+
|
10
|
+
def caller_namespace_root
|
11
|
+
namespace_root binding.of_caller(3).eval('self.class.name')
|
12
|
+
end
|
13
|
+
private :caller_namespace_root
|
14
|
+
|
15
|
+
def class_namespace_root
|
16
|
+
namespace_root self.name
|
17
|
+
end
|
18
|
+
private :class_namespace_root
|
19
|
+
|
20
|
+
def internal_methods
|
21
|
+
@internal_methods ||= protected_methods
|
22
|
+
end
|
23
|
+
private :internal_methods
|
24
|
+
|
25
|
+
def internal_instance_methods
|
26
|
+
@internal_instance_methods ||= protected_instance_methods
|
27
|
+
end
|
28
|
+
private :internal_instance_methods
|
29
|
+
|
30
|
+
def namespace_root(namespace)
|
31
|
+
namespace.sub!(/\A([A-Z][a-z_]*)((::.*))*\z/, '\\1')
|
32
|
+
end
|
33
|
+
private :namespace_root
|
34
|
+
|
35
|
+
def new *args
|
36
|
+
caller_internal? ? set_internal_instance_methods_public! : set_internal_instance_methods_protected!
|
37
|
+
super *args
|
38
|
+
end
|
39
|
+
public :new
|
40
|
+
|
41
|
+
def set_internal_class_methods_protected!
|
42
|
+
internal_methods.each { |m| self.instance_eval("class << self; protected :#{m}; end") }
|
43
|
+
end
|
44
|
+
private :set_internal_class_methods_protected!
|
45
|
+
|
46
|
+
def set_internal_class_methods_public!
|
47
|
+
internal_methods.each { |m| self.instance_eval("class << self; public :#{m}; end") }
|
48
|
+
end
|
49
|
+
private :set_internal_class_methods_public!
|
50
|
+
|
51
|
+
def set_internal_instance_methods_protected!
|
52
|
+
internal_instance_methods.each { |m| protected m }
|
53
|
+
end
|
54
|
+
private :set_internal_instance_methods_protected!
|
55
|
+
|
56
|
+
def set_internal_instance_methods_public!
|
57
|
+
internal_instance_methods.each { |m| public m }
|
58
|
+
end
|
59
|
+
private :set_internal_instance_methods_public!
|
60
|
+
|
61
|
+
alias_method :old_public_method_defined?, :public_method_defined?
|
62
|
+
def public_method_defined?(*args)
|
63
|
+
old_public_method_defined?(*args)
|
64
|
+
end
|
65
|
+
public :public_method_defined?
|
66
|
+
|
67
|
+
alias_method :old_public_methods, :public_methods
|
68
|
+
def public_methods
|
69
|
+
ret = old_public_methods
|
70
|
+
ret << internal_methods if caller_internal?
|
71
|
+
end
|
72
|
+
public :public_methods
|
73
|
+
|
74
|
+
alias_method :old_protected_methods, :protected_methods
|
75
|
+
def protected_methods
|
76
|
+
caller_internal? ? [] : internal_methods
|
77
|
+
end
|
78
|
+
protected :protected_methods
|
79
|
+
|
80
|
+
def work_internal_class_methods!
|
81
|
+
internal_methods.each do |m|
|
82
|
+
self.instance_eval("alias_method old_#{m} #{m}; def #{m}(*args); raise NoMethodError if !caller_internal?; old_#{m}(*args); end")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
private :work_internal_class_methods!
|
86
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
2
|
+
|
3
|
+
require 'pry'
|
4
|
+
require 'minitest'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'internal'
|
7
|
+
|
8
|
+
module Foo
|
9
|
+
end
|
10
|
+
|
11
|
+
class Foo::Bar
|
12
|
+
extend Internal
|
13
|
+
|
14
|
+
def initialize(*args)
|
15
|
+
@args = args
|
16
|
+
end
|
17
|
+
|
18
|
+
def bar
|
19
|
+
@args
|
20
|
+
end
|
21
|
+
protected :bar
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def baz
|
25
|
+
'baz'
|
26
|
+
end
|
27
|
+
public :baz
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Foo::Baz
|
32
|
+
def self.baz
|
33
|
+
Foo::Bar.baz
|
34
|
+
end
|
35
|
+
|
36
|
+
def bar(*args)
|
37
|
+
Foo::Bar.new(*args).bar
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Bar
|
42
|
+
def self.baz
|
43
|
+
Foo::Bar.baz
|
44
|
+
end
|
45
|
+
|
46
|
+
def bar(*args)
|
47
|
+
Foo::Bar.new(*args).bar
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class InternalTest < Minitest::Test
|
52
|
+
def test_internal_class_instance_method
|
53
|
+
assert_equal ::Foo::Baz.new.bar('a'), ['a']
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_internal_class_singleton_method
|
57
|
+
assert_equal ::Foo::Baz.baz, 'baz'
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_external_class_instance_method
|
61
|
+
assert_raises(NoMethodError) { ::Bar.new.bar('a') }
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_external_class_singleton_method
|
65
|
+
assert_raises(NoMethodError) { ::Bar.baz }
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: internal
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0alpha01
|
5
|
+
prerelease: 5
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Daniel da Silva Ferreira (dsferreira)
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-06-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sender
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: binding_of_caller
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
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: bundler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.3'
|
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: '1.3'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '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: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: minitest
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: Internal
|
95
|
+
email:
|
96
|
+
- danieldasilvaferreira@gmail.com
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- .rvmrc
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- design_rationale.md
|
108
|
+
- internal.gemspec
|
109
|
+
- lib/internal.rb
|
110
|
+
- lib/internal/version.rb
|
111
|
+
- test/internal_test.rb
|
112
|
+
homepage: ''
|
113
|
+
licenses:
|
114
|
+
- MIT
|
115
|
+
post_install_message:
|
116
|
+
rdoc_options: []
|
117
|
+
require_paths:
|
118
|
+
- lib
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
segments:
|
126
|
+
- 0
|
127
|
+
hash: 4162978592114588374
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>'
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 1.3.1
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 1.8.25
|
137
|
+
signing_key:
|
138
|
+
specification_version: 3
|
139
|
+
summary: Makes a class, module or method internal
|
140
|
+
test_files:
|
141
|
+
- test/internal_test.rb
|