Crystal get raised Exception's class - crystal-lang

I was expecting that typeof(...) would give me the exact class, but when rescuing an Exception typeof(MyCustomException) just returns Exception
class A < Exception; end
class B < A; end
begin
raise B.new
rescue e
puts typeof(e) # => Exception
end
Whereas puts typeof(B.new) returns B as expected

As per https://github.com/bararchy on the issue I created here: https://github.com/crystal-lang/crystal/issues/4597
I think that typeof is indeed Exception, but .class will give you what you want , I could be mistaken but I think that is intended
So yeah e.class returns B

rescue e does not restrict the type of exception handled by this rescue block. Therefor e can be any exception type.
If you only want to handle exceptions of type B, you should add a type restriction rescue e : B. Then, typeof(e) will be B.

Related

Cast OWL-S condition to SWRL

I want to cast some OWL-S conditions to SWRL, the cast is done but the result manipulation returns nullpointerexception. Here the code :
final OWLIndividualList<Condition> cs = service.getProfile().getConditions();
final ArrayList<ArrayList<URI>> conditions = new ArrayList<ArrayList<URI>>();
for (final Condition<?> c : cs){
if (c.canCastTo(Condition.SWRL.class)){ // is it a SWRL condition?
final Condition.SWRL sc = c.castTo(Condition.SWRL.class);
for (final Atom a : sc.getBody()){...........
the last line returns :
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
Can anyone help me to deal with this?
This issue is not linked to the java code but to the OWLS-S file syntaxe.
you can resolve this issue by replacing:
<expr:expressionBody rdf:parseType="Literal">
which hold the SWRL precondition (or eventually the result), by:
<expr:expressionObject>

Crystal compiler does not detect that object is not nil

I have the following class :
class X
property son, val
def initialize(#val : Int32)
#son = nil.as X?
end
def add(other : X?)
unless other.nil?
if #son.nil?
#son = other
else
#son.add(other)
end
end
end
end
x = X.new 5
x.add(nil)
x.add(X.new 3)
But when I try to build I get
Showing last frame. Use --error-trace for full trace.
In nil-test.cr:12:22
12 | #son.add(other)
^------
Error: undefined method 'include' for Nil (compile-time type is (X | Nil))
According to the manual, this is exactly the kind of situation where the compiler should recognize that #son cannot be nil in the else branch, yet it apparently fails to do so.
What am I doing wrong ?
Note : using #son.not_nil!.add(other) works, I'm just asking why the compiler can't do without.
That only works for local variables, not instance variables - since the instance variables may be mutated by another fiber between the condition and you accessing the variable. See this section (under "Limitations") in the Crystal docs.
You can do it like this, assigning the instance variable to a local variable that will not change out from under you:
def add(other : X?)
unless other.nil?
if s = #son
s.add(other)
else
#son = other
end
end
end

OCaml: define composite exception type with line number information

I am working on some OCaml code and I would like to define a composite exception type; as follows:
type exceptbase = string * string
exception UndefinedTyp of exceptbase
I would like the first element of such exception to be the line number information.
However, when I use some exception handling code below, it cannot be compiled.
raise UndefinedTyp (__LOC__, "some exception messages")
So here are my questions:
How to correctly define such composite exception type?
Note that since the first element is always the __LOC__, is there any way I can save the effort and use __LOC__ to pre-occupy the first element?
On the second point, within the vanilla OCaml, I am afraid it is impossible to omit __LOC__ argument.
But you can write a perprocessor to rewrite Undefined "some exception message" to Undefined (__LOC__, "some exception message"). Today we use PPX framework to write such a preprocessor.
BTW, OCaml's exception backtrace contains the location of raised exceptions. Setting environment variable OCAMLRUNPARAM=b, OCaml runtime prints it with source code locations when an uncaught exception terminates the program. Programatically Printexc module provides some APIs to obtain it.
You just need some parentheses:
# type exceptbase = string * string
exception UndefinedTyp of exceptbase;;
type exceptbase = string * string
exception UndefinedTyp of exceptbase
# raise (UndefinedTyp (__LOC__, "some exception message"));;
Exception:
UndefinedTyp
("File \"//toplevel//\", line 2, characters -13--6",
"some exception message").

RSpec it block with variable name

I have a function get_type that returns a string given an int:
def get_type(integer)
types = [...]
return types[integer]
end
When testing with RSpec, I tried doing the following:
describe 'function' do
context 'on valid input'
let(:input){ 2 }
let(:type){ 'large' }
let(:result){ get_type input }
it{ expect(result).to eq(type) }
end
end
However, this gives the message:
function on valid input should eq "large"
without any mention to the input, thus sounding like the function should always return "large".
How should this message be changed to say something like:
function on valid input should eq type
or another meaningful message? I could name the it block:
it 'should have the correct type' do
expect(result).to eq(type)
end
but is there a nicer way to do this without essentially typing out the test twice?
I think the unhelpful message should be considered a smell - you're headed down a road where every test is just expect(result).to eq(expected) with a wall of let. To my mind this is overuse of let - I don't think you gain anything over
describe 'function' do
context 'on valid input' do
it{ expect(get_type(2)).to eq('large') }
end
end
Which would produce a more helpful failure message. I would keep let for when the expressions are more complex or when I can give them a better name (eg a hash of attributes called valid_attributes)

scope not working on Mongoid (undefined method `to_criteria')

I invoke ReleaseSchedule.next_release in other controller
and got the following error
NoMethodError (undefined method `to_criteria' for #<ReleaseSchedule:0x007f9cfafbfe70>):
app/controllers/weekly_query_controller.rb:15:in `next_release'
releae_schedule.rb
class ReleaseSchedule
scope :next_release, ->(){ ReleaseSchedule.where(:release_date.gte => Time.now).without(:_id, :created_at, :updated_at).first }
end
That's not really a scope at all, that's just a class method wrapped up to look like a scope. There are two problems:
You're saying ReleaseSchedule.where(...) so you can't chain the "scope" (i.e. ReleaseSchedule.where(...).next_release won't do what it is supposed to do).
Your "scope" ends in first so it won't return a query, it just returns a single instance.
2 is probably where your NoMethodError comes from.
If you really want it to be a scope for some reason then you'd say:
# No `first` or explicit class reference in here.
scope :next_release, -> { where(:release_date.gte => Time.now).without(:_id, :created_at, :updated_at) }
and use it as:
# The `first` goes here instead.
r = ReleaseSchedule.next_release.first
But really, you just want a class method:
def self.next_release
where(:release_date.gte => Time.now).without(:_id, :created_at, :updated_at).first
end
The scope macro is, after all, just a fancy way to build class methods. The only reason we have scope is to express an intent (i.e. to build queries piece by piece) and what you're doing doesn't match that intent.