I have a weird situation with unit tests that would be easily solved by a bit of an hack, and would like to know if this is easily doable as a temporary fix before tackling a major rewrite.
import Foundation
class Foo : NSObject {
func bar() -> Void {
// third-party code
}
}
Is there any way that given Foo.bar would return the string "-[Foo bar]"
Edit: I didn't explain my situation well, sorry. I'm looking for something like a function:
MyStringifyingFunction(Foo.bar) // returns "-[Foo bar]"
This will be used to compare with name of a XCTest instance which is populated with the string "-[MyTestClass testMethodOne]" for example.
Related
Suppose I've a class called Devil
class Devil
and I've method called support
fun <T> support(t : T){
}
I want to restrict this function to only accept classes other than Devil (all classes in the world, but not Devil). Something like
fun <T except Devil> support(t : T){
}
How do I do this in Kotlin? Is this even possible?
This is very likely an XY problem, so please do not apply this solution without considering something else.
One way to achieve this is to declare a non-generic overload of support() with the explicit type Devil, and deprecate that function with ERROR level:
fun <T> support(t: T) {
// do your stuff
}
#Deprecated("support() cannot be used with type Devil", level = DeprecationLevel.ERROR)
fun support(devil: Devil) {
error("NOPE.")
}
Note that this would also exclude subtypes of Devil - which is not explicitly stated in your question, but might be what you want.
However, nothing prevents users from working around it by explicitly calling the generic overload by specifying a type in <...>:
support<Devil>(Devil()) // compiles fine
support<Any>(Devil()) // compiles fine
Similarly, as #gidds pointed out, this approach also doesn't prevent compilation if you pass in a variable with a static type that is not Devil even if it holds an instance of Devil (because the compiler will choose the generic overload in that case):
val hiddenDevil: Any = Devil()
support(hiddenDevil) // compiles fine
I tried to make abstract class for testing because I found weird problem for using generics
abstract class Test<T> {
open fun hello(vararg data: T) {
print("Default function")
}
}
This very simple abstract class has one opened method with vararg keyword. Problem can be reproduced by making another class which extends Test class.
class Hello : Test<Int>() {
//Problem 1
override fun hello(vararg data: Int) {
super.hello(*data) //Problem 2
println("Override function")
}
}
About first problem, Kotlin says method doesn't override anything even though this method surely overrides something. Weirdly, this error happens randomly, so I can't tell exact way to reproduce this bug
This error got removed when I add some codes (like really simple code such as println(), etc), but when you compile, it causes same error again.
About second problem, super.hello(*data) causes problem because this requires Array<out Int>, but found parameter is IntArray. I think Kotlin is considering IntArray and Array<*> as different class, but it shouldn't act like this...
I'm using Kotlin 1.4.10 which seems the latest version according to this site.
I'm posting this to check if these 2 problems are bug or if I did something incorrectly because when I change generic to String, all problems get removed.
Are there any mistakes I made in these sample codes above?
Known issue: https://youtrack.jetbrains.com/issue/KT-9495
As a workaround, you can use the boxed java.lang.Integer.
class Hello : Test<Integer>() {
override fun hello(vararg data: Integer) {
super.hello(*data)
println("Override function")
}
}
Here is an example of what I'd like to achieve:
open class A {
open fun Int.foo() {
print("foo")
}
}
object B: A() {
val number = 5;
override fun Int.foo() {
print("overriden foo");
// I want to call the A.(Int.foo())
}
}
B.number.foo(); //outputs: "foooverriden foo"
First of all, does anything like this exist? Can I somehow assume number to be in the context of class A in its override method? How would I write this?
The more I think about it the more it twists my mind. Of course, you cannot call number.super.foo() because super for number is kotlin.Number. You cannot cast it to A because Int has nothing to do with A. The only way I can think about solving this to somehow import the extension function itself and rename it with as, but I cannot do that here since it is inside a class, so I cannot just import it. Any suggestions?
My use case for this is that I have a class where I manipulate some data, then in special cases, I want to manipulate it differently, but fall back to the original code as the last option. I could use normal functions instead of extension functions of course, but in my case, it comes natural to use extension functions, so I wanted to see if this could be achieved somehow.
It looks like this is impossible so far, I'm afraid.
There's an open issue for this on JetBrains' issue-tracking system: KT-11488. There's a Kotlin work-around there, though that needs tweaks to the class designs.
(Also discussed on the JetBrains discussion board. That mentions another workaround requiring a Java class.)
override fun Int.foo() {
print("overriden foo")
with (A()) {
foo()
}
}
Of course this is a bit of a hack and will get worse if A has some state which foo() depends on, which you'll then need to set manually.
Is there a way to test private methods in Raku?
I understand that one should ideally define their tests targeting the public methods, but is there a way to do it "the wrong way"? :)
I initially thought about defining a subclass for the Testing that inherited from the class I wanted to test and do the tests there, but it seems that private methods are not inherited.
Then I saw the 'trusts' routine, but I wouldn't want to reference a Testing class on any of the classes of the code.
Is there something like changing the 'private' property of a method via introspection?
What would be the best way to call/test a private method?
This can be done using introspection.
Consider this is the class you want to test:
class SomeClass {
has Int $!attribute;
method set-value(Int $value) returns Nil {
$!attribute = $value;
return;
}
method get-value returns Int {
return $!attribute;
}
# Private method
method !increase-value-by(Int $extra) returns Nil {
$!attribute += $extra;
return;
}
}
You may create a test like this:
use Test;
use SomeClass;
plan 3;
my SomeClass $some-class = SomeClass.new;
my Method:D $increase-value = $some-class.^find_private_method: 'increase-value-by';
$some-class.set-value: 1;
$increase-value($some-class, 4);
is $some-class.get-value, 5, '1+4 = 5';
$increase-value($some-class, 5);
is $some-class.get-value, 10, '5+5 = 10';
my SomeClass $a-new-class = SomeClass.new;
$a-new-class.set-value: 0;
$increase-value($a-new-class, -1);
is $a-new-class.get-value, -1, '0+(-1) = -1; The method can be used on a new class';
done-testing;
You first create an instance of the class and the use ^find_private_method to get its private Method. Then you can call that Method by passing an instance of a class as the first parameter.
There's a more complete explanation on this answer:
How do you access private methods or attributes from outside the type they belong to?
A fresh cup of tea and #Julio's and #JJ's answers inspired the following:
class SomeClass { method !private ($foo) { say $foo } }
use MONKEY-TYPING; augment class SomeClass { trusts GLOBAL }
my SomeClass $some-class = SomeClass.new;
$some-class!SomeClass::private(42); # 42
My solution tweaks the class using monkey typing. Monkey typing is a generally dodgy thing to do (hence the LOUD pragma). But it seems tailor made for a case just like this. Augment the class with a trusts GLOBAL and Bob's your Uncle.
Raku requires the SomeClass:: qualification for this to work. (Perhaps when RakuAST macros arrive there'll be a tidy way to get around that.) My inclination is to think that having to write a class qualification is OK, and the above solution is much better than the following, but YMMV...
Perhaps, instead:
use MONKEY-TYPING;
augment class SomeClass {
multi method FALLBACK ($name where .starts-with('!!!'), |args) {
.(self, |args) with $?CLASS.^find_private_method: $name.substr: 3
}
}
and then:
$some-class.'!!!private'(42); # 42
I've used:
A multi for the FALLBACK, and have required that the method name string starts with !!!;
A regular method call (. not !);
Calling the method by a string version of its name.
The multi and !!! is in case the class being tested already has one or more FALLBACK methods declared.
A convention of prepending !!! seems more or less guaranteed to ensure that the testing code will never interfere with how the class is supposed to work. (In particular, if there were some call to a private method that didn't exist, and there was existing FALLBACK handling, it would handle that case without this monkey FALLBACK getting involved.)
It should also alert anyone reading the test code that something odd is going on, in the incredibly unlikely case that something weird did start happening, either because I'm missing something that I just can't see, or because some FALLBACK code within a class just so happened to use the same convention.
Besides using introspection, you can try and use a external helper role to access all private methods and call them directly. For instance:
role Privateer {
method test-private-method ( $method-name, |c ) {
self!"$method-name"(|c);
}
}
class Privateed does Privateer {
method !private() { return "⌣" }
}
my $obj = Privateed.new;
say $obj.test-private-method( "private" );
The key here is to call a method by name, which you can do with public and private methods, although for private methods you need to use their special syntax self!.
Is there an equivalent of NSStringFromClass in Swift that gives a user-readable version of the class name? I've tried to use it with a native Swift class I created, but as you can see, the result seems to be the compiler's internal representation of the class name:
println(NSStringFromClass(MyClass.self))
Result:
_TtC5test7MyClass
I've tried adding the #objc attribute to the class, and making it a subclass of NSObject, but it makes no difference. I've discovered that if I replace MyClass with an Objective-C class of the same name, and import this in the bridging header, it gives me 'MyClass', but this shouldn't be necessary.
Another option would be to make a protocol for this, which each class I want to use in this way must conform to:
protocol Nameable {
class var className: String { get }
}
However, it would be easier to have a built-in way to do this in the language.
You can now just do:
String(MyClass)
new format based on xcode 6 beta 5.
(project_name).(class_name)
func getName(classType:AnyClass) -> String {
let classString = NSStringFromClass(classType.self)
let range = classString.rangeOfString(".", options: NSStringCompareOptions.CaseInsensitiveSearch, range: Range<String.Index>(start:classString.startIndex, end: classString.endIndex), locale: nil)
return classString.substringFromIndex(range!.endIndex)
}
Latest 6.3 Xcode Swift 1.2
if you need an extension or you can put this on any common object:
public extension NSObject{
public class var nameOfClass: String{
return NSStringFromClass(self).componentsSeparatedByString(".").last!
}
public var nameOfClass: String{
return NSStringFromClass(self.dynamicType).componentsSeparatedByString(".").last!
}
}
Swift 3
type(of: self) prints ModuleName.ClassName
String(describing: type(of: self)) prints ClassName
At the moment, there's no reliable way to do this. See an Apple developer's comment on https://devforums.apple.com/thread/227425
Swift does not currently have much in the way of introspection.
There is some introspection machinery that is used for the
playgrounds. I don't know if that is intended to be API.
Some Swift
methods and variables can be examined using the Objective-C runtime's
introspection. That's likely to be the best solution today.
Swift does have the notion of a metatype, somewhat analogous to the Class type in Objective C. You can find it using TypeName.self, e.g.:
class Foo {
#required init() {
}
}
var normalFoo : Foo = Foo()
var fooType : Foo.Type = Foo.self;
var fooFromMetatype : Foo = fooType();
Perhaps, by release time, metatypes will include more introspection abilities. I suggest filing a Radar feature request for this.
In Swift 2 beta 4 you can get to the information via the type object:
let className = "\(String.self)" // gives: "Swift.String"
or if you have an instance:
let s = "Hello World"
let className = "\(s.dynamicType)" // gives: "Swift.String"
You get the Module.Class result, like:
Swift.String
ABC.MyGenericClass<Swift.Int>
Funny enough the Type object returned does not seem to conform to the CustomStringConvertible protocol. Hence it has no 'description' property, though the "" pattern still does the right thing.
P.S.: Before b4 the same could be accomplished via reflect(obj.dynamicType).summary.
In Swift v3.0, this worked for me:
String.init(describing: self.self)
----- Updated -----
As #ThomasW mentioned, for Swift 4, we need to use String(describing:type(of:self))
----- Old post ----
I prefer to use String(self.dynamicType)
Use it in my project https://github.com/JakeLin/SwiftWeather/blob/e7165b0919dda53fd7fcba9b43fdfe150d73c6f8/SwiftWeather/ForecastView.swift#L135
If you want to have only the name of the class in swift you can parse the string returned by NSStringFromClass().
This is done in nameOfClass.swift of the INSwift Github repository:
https://github.com/indieSoftware/INSwift
You shouls now be able to use the following to retrieve the class name in swift
let nameSpaceClassName = NSStringFromClass(RWTCountryPopoverViewController.self)
let className = nameSpaceClassName.componentsSeparatedByString(".").last! as String
This is a bit shorter. No need of NSStringFromClass
MyObject.self.description().componentsSeparatedByString(".").last!
Here is Swift 3+, Xcode 8+ example with code:
class MySuperbClass{
let a = 4
func getClassName() -> String? {
return String(describing: type(of:self)).components(separatedBy: ".").first
}
}
let className = String(describing: type(of:MySuperbClass.self)).components(separatedBy: ".").first
//className = "MySuperbClass"
let classNameFromObject = MySuperbClass().getClassName()
//classNameFromObject = "MySuperbClass"
Swift 4
super.init(nibName:String(describing:MyClass.self), bundle: nil)
myObject.description().componentsSeparatedByString(" ").first!
This is not exactly what you want - it will add an unwanted leading '<' and trailing ':'. But when I am debugging I value speed over neatness so this quick + dirty trick worked for me.
Swift 3
NSStringFromClass(self).components(separatedBy: ".").last!
In latest version of swift, below works for me:
NSStringFromClass(type(of: device!.self))