Avoid calling to_s on ancestors, which can become expensive and slow
Sorry for the confusion; I'm switching branches on this PR with this new approach, so I'm closing my old PR and opening this one.
This approach still fails in one case - when you call to_s on an anonymous class, you get a name like <Class:xxxxxx>. I'm not aware of a safe / sane way to reify an object from that string. The API currently supports passing in those strings in the publisher, but this breaks that ability.
Any ideas?
Coverage increased (+0.004%) to 99.878% when pulling 99a879b42aa33bd75f5083fd514df60f6d947df0 on g2crowd:faster-ancestor-lookup into 8773f751fa94e2c75e883c20111c852921bd70ba on krisleech:master.
This approach still fails in one case - when you call to_s on an anonymous class, you get a name like Class:xxxxxx.
I guess the problem is the xxxxx part is different every time to_s is called?
I'm not aware of a safe / sane way to reify an object from that string. The API currently supports passing in those strings in the publisher, but this breaks that ability.
Yes, it wouldn't be possible to go from a string to the anonymous class. Does it still work okay if a Class is passed instead of a String? Or are you saying that is what this change breaks, i.e. is not backwards compatible?
Does it still work okay if a Class is passed instead of a String? Or are you saying that is what this change breaks, i.e. is not backwards compatible?
Works great when the class is available. My concern is backwards compatibility - when I made this change it broke a different spec, and I wasn't sure how to proceed.
Sorry for long delays in responding. I've been using my changes in my own project with no hiccups so I lost sight of this.
To solve the issue with the anonymous class, you can split allowed_classes into 2 groups: constantized_classes and stringified_classes. Only class string in which Object.get_const raises error (for example: Class.new.to_s) is moved into stringified_classes, everything else is moved to constantized_classes.
Then publisher_in_scope? can be implemented as follow:
(constantized_classes.empty? && stringified_classes.empty?) ||
(publisher.class.ancestors & constantized_classes).present? ||
(
stringified_classes.present? &&
(publisher.class.ancestors.map(&:to_s) & stringified_classes).present?
)
In this case, to_s is not avoidable if there is anything in stringified_classes.