Skip to content

Commit

Permalink
Merge pull request #2194 from natalie-lang/protected_methods
Browse files Browse the repository at this point in the history
Add Kernel#protected_methods
  • Loading branch information
seven1m committed Jul 7, 2024
2 parents 29f62a1 + f6b7aa4 commit 18ee0f0
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 22 deletions.
2 changes: 2 additions & 0 deletions include/natalie/kernel_module.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class KernelModule : public Object {
Value methods(Env *env, Value regular_val);
bool neqtilde(Env *, Value);
Value private_methods(Env *, Value = nullptr);
Value protected_methods(Env *, Value = nullptr);
Value public_methods(Env *, Value = nullptr);
Value remove_instance_variable(Env *env, Value name_val);
Value tap(Env *env, Block *block);
bool is_a(Env *env, Value module);
Expand Down
3 changes: 2 additions & 1 deletion lib/natalie/compiler/binding_gen.rb
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,8 @@ def generate_name
gen.binding('Kernel', 'method', 'KernelModule', 'method', argc: 1, pass_env: true, pass_block: false, return_type: :Object)
gen.binding('Kernel', 'methods', 'KernelModule', 'methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object)
gen.binding('Kernel', 'private_methods', 'KernelModule', 'private_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object)
gen.binding('Kernel', 'public_methods', 'KernelModule', 'methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object)
gen.binding('Kernel', 'protected_methods', 'KernelModule', 'protected_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object)
gen.binding('Kernel', 'public_methods', 'KernelModule', 'public_methods', argc: 0..1, pass_env: true, pass_block: false, return_type: :Object)
gen.binding('Kernel', 'public_send', 'Object', 'public_send', argc: 1.., pass_env: true, pass_block: true, return_type: :Object)
gen.binding('Kernel', 'object_id', 'Object', 'object_id', argc: 0, pass_env: false, pass_block: false, return_type: :int)
gen.binding('Kernel', 'remove_instance_variable', 'KernelModule', 'remove_instance_variable', argc: 1, pass_env: true, pass_block: false, return_type: :Object)
Expand Down
10 changes: 3 additions & 7 deletions spec/core/kernel/private_methods_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
m = KernelSpecs::Methods.private_methods(false)
m.should include(:shichi)
m = KernelSpecs::Methods.new.private_methods(false)
NATFIXME 'returns a list of the names of privately accessible methods in the object', exception: SpecFailedException do
m.should include(:juu_shi)
end
m.should include(:juu_shi)
end

it "returns a list of the names of privately accessible methods in the object and its ancestors and mixed-in modules" do
Expand Down Expand Up @@ -47,10 +45,8 @@

describe :kernel_private_methods_with_falsy, shared: true do
it "returns a list of private methods in without its ancestors" do
NATFIXME 'returns a list of private methods in without its ancestors', exception: SpecFailedException do
ReflectSpecs::F.private_methods(@object).select{|m|/_pri\z/ =~ m}.sort.should == [:ds_pri, :fs_pri]
ReflectSpecs::F.new.private_methods(@object).should == [:f_pri]
end
ReflectSpecs::F.private_methods(@object).select{|m|/_pri\z/ =~ m}.sort.should == [:ds_pri, :fs_pri]
ReflectSpecs::F.new.private_methods(@object).should == [:f_pri]
end
end

Expand Down
69 changes: 69 additions & 0 deletions spec/core/kernel/protected_methods_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative '../../fixtures/reflection'

# TODO: rewrite

# The reason why having include() is to show the specification explicitly.
# You should use have_protected_method() with the exception of this spec.
describe "Kernel#protected_methods" do
it "returns a list of the names of protected methods accessible in the object" do
KernelSpecs::Methods.protected_methods(false).sort.should include(:juu_ichi)
KernelSpecs::Methods.new.protected_methods(false).should include(:ku)
end

it "returns a list of the names of protected methods accessible in the object and from its ancestors and mixed-in modules" do
l1 = KernelSpecs::Methods.protected_methods(false)
l2 = KernelSpecs::Methods.protected_methods
(l1 & l2).should include(:juu_ichi)
KernelSpecs::Methods.new.protected_methods.should include(:ku)
end

it "returns methods mixed in to the metaclass" do
m = KernelSpecs::Methods.new
m.extend(KernelSpecs::Methods::MetaclassMethods)
m.protected_methods.should include(:nopeeking)
end
end

describe :kernel_protected_methods_supers, shared: true do
it "returns a unique list for an object extended by a module" do
m = ReflectSpecs.oed.protected_methods(*@object)
m.select { |x| x == :pro }.sort.should == [:pro]
end

it "returns a unique list for a class including a module" do
m = ReflectSpecs::D.new.protected_methods(*@object)
m.select { |x| x == :pro }.sort.should == [:pro]
end

it "returns a unique list for a subclass of a class that includes a module" do
m = ReflectSpecs::E.new.protected_methods(*@object)
m.select { |x| x == :pro }.sort.should == [:pro]
end
end

describe :kernel_protected_methods_with_falsy, shared: true do
it "returns a list of protected methods in without its ancestors" do
ReflectSpecs::F.protected_methods(@object).select{|m|/_pro\z/ =~ m}.sort.should == [:ds_pro, :fs_pro]
ReflectSpecs::F.new.protected_methods(@object).should == [:f_pro]
end
end

describe "Kernel#protected_methods" do
describe "when not passed an argument" do
it_behaves_like :kernel_protected_methods_supers, nil, []
end

describe "when passed true" do
it_behaves_like :kernel_protected_methods_supers, nil, true
end

describe "when passed false" do
it_behaves_like :kernel_protected_methods_with_falsy, nil, false
end

describe "when passed nil" do
it_behaves_like :kernel_protected_methods_with_falsy, nil, nil
end
end
76 changes: 76 additions & 0 deletions spec/core/kernel/public_methods_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative '../../fixtures/reflection'

# TODO: rewrite
describe "Kernel#public_methods" do
it "returns a list of the names of publicly accessible methods in the object" do
KernelSpecs::Methods.public_methods(false).sort.should include(:hachi,
:ichi, :juu, :juu_ni, :roku, :san, :shi)
KernelSpecs::Methods.new.public_methods(false).sort.should include(:juu_san, :ni)
end

it "returns a list of names without protected accessible methods in the object" do
KernelSpecs::Methods.public_methods(false).sort.should_not include(:juu_ichi)
KernelSpecs::Methods.new.public_methods(false).sort.should_not include(:ku)
end

it "returns a list of the names of publicly accessible methods in the object and its ancestors and mixed-in modules" do
(KernelSpecs::Methods.public_methods(false) & KernelSpecs::Methods.public_methods).sort.should include(
:hachi, :ichi, :juu, :juu_ni, :roku, :san, :shi)
m = KernelSpecs::Methods.new.public_methods
m.should include(:ni, :juu_san)
end

it "returns methods mixed in to the metaclass" do
m = KernelSpecs::Methods.new
m.extend(KernelSpecs::Methods::MetaclassMethods)
m.public_methods.should include(:peekaboo)
end

it "returns public methods for immediates" do
10.public_methods.should include(:divmod)
end
end

describe :kernel_public_methods_supers, shared: true do
it "returns a unique list for an object extended by a module" do
m = ReflectSpecs.oed.public_methods(*@object)
m.select { |x| x == :pub }.sort.should == [:pub]
end

it "returns a unique list for a class including a module" do
m = ReflectSpecs::D.new.public_methods(*@object)
m.select { |x| x == :pub }.sort.should == [:pub]
end

it "returns a unique list for a subclass of a class that includes a module" do
m = ReflectSpecs::E.new.public_methods(*@object)
m.select { |x| x == :pub }.sort.should == [:pub]
end
end

describe :kernel_public_methods_with_falsy, shared: true do
it "returns a list of public methods in without its ancestors" do
ReflectSpecs::F.public_methods(@object).select{|m|/_pub\z/ =~ m}.sort.should == [:ds_pub, :fs_pub]
ReflectSpecs::F.new.public_methods(@object).should == [:f_pub]
end
end

describe "Kernel#public_methods" do
describe "when not passed an argument" do
it_behaves_like :kernel_public_methods_supers, nil, []
end

describe "when passed true" do
it_behaves_like :kernel_public_methods_supers, nil, true
end

describe "when passed false" do
it_behaves_like :kernel_public_methods_with_falsy, nil, false
end

describe "when passed nil" do
it_behaves_like :kernel_public_methods_with_falsy, nil, nil
end
end
33 changes: 19 additions & 14 deletions src/kernel_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,20 +526,25 @@ Value KernelModule::print(Env *env, Args args) {
return _stdout->send(env, "write"_s, args);
}

Value KernelModule::private_methods(Env *env, Value regular_val) {
bool regular = regular_val ? regular_val->is_truthy() : true;
if (regular) {
if (singleton_class()) {
return singleton_class()->private_instance_methods(env, TrueObject::the());
} else {
return klass()->private_instance_methods(env, TrueObject::the());
}
}
if (singleton_class()) {
return singleton_class()->private_instance_methods(env, FalseObject::the());
} else {
return new ArrayObject {};
}
Value KernelModule::private_methods(Env *env, Value recur) {
if (singleton_class())
return singleton_class()->private_instance_methods(env, recur);
else
return klass()->private_instance_methods(env, FalseObject::the());
}

Value KernelModule::protected_methods(Env *env, Value recur) {
if (singleton_class())
return singleton_class()->protected_instance_methods(env, recur);
else
return klass()->protected_instance_methods(env, FalseObject::the());
}

Value KernelModule::public_methods(Env *env, Value recur) {
if (singleton_class())
return singleton_class()->public_instance_methods(env, recur);
else
return klass()->public_instance_methods(env, FalseObject::the());
}

Value KernelModule::proc(Env *env, Block *block) {
Expand Down

0 comments on commit 18ee0f0

Please sign in to comment.