Here's my crystal code, in snippets, but I think it's all there:
# spec_helper.rb
def fixtures
rawhash = JSON.parse(File.read("spec/fixtures/state3.json"))
rules = rawhash["rules"]
id = rules.as_h.keys[0]
hash = rules[id]
return id, hash
end
# rule_spec.rb
key, hash = fixtures
rule = Rule.new(key, hash)
rule.array(["name"])[0].must_equal "RpsIphone"
# rule.rb
class Rule < HueResource
getter :detail, :on, :name, :lights
def initialize(key, hashvalue)
super(key, hashvalue)
@detail = "#{hashvalue["conditions"].length} conds => #{hashvalue["actions"].length} acts"
@state.merge! ({"on" => hash_value["status"], "name" => @name, "detail" => @detail})
gen_reskey("r")
end
...
end
# hue resource.rb
class HueResource
def initialize(key, hash_value)
@hash_value = hash_value.as_h
@lastupdated = @hash_value["state"]["lastupdated"]
@detail = hash_value["type"]
@name = hash_value["name"]
@state = { "key" => key, "lastupdated" => @lastupdated, "detail" => @detail, "name" => @name}
end
def gen_reskey(detail)
@state.merge!({ "id" => detail + @state["key"]})
end
end
And here's the error:
[Running] crystal "/Users/pitosalas/mydev/crystalplay/spec/rule_spec.cr"
Error in spec/rule_spec.cr:7: instantiating 'Rule.class#new(String, JSON::Any)'
rule = Rule.new(key, hash)
[32;1m^~~[0m
in src/rule.cr:7: instantiating 'super(String, JSON::Any)'
super(key, hashvalue)
[32;1m^~~~~[0m
in src/hue_resource.cr:3: [1mCan't infer the type of instance variable '@hash_value' of Rule
The type of a instance variable, if not declared explicitly with
`@hash_value : Type`, is inferred from assignments to it across
the whole program.
Now it seems to me that in the constructors, @hash_value is assigned to hash_value.as_h so it would know the type from there on.
Also feel free to point out Crystal stylistic or idiomatic comments!
The compiler can't infer ivar types from the return type of method calls (like hash_value.as_h
). The reference of Type inference lists all rules where the compiler can infer ivar types.
Infering the type from method calls is probably not impossible, but more complicated. It might come to the language at some point, but for now you'll have to use an explicit type annotation such as @hash_value : Hash(JSON::Any, JSON::Any)
.