diff --git a/src/crystal/properties.cr b/src/crystal/properties.cr new file mode 100644 index 000000000000..8c9e623b6096 --- /dev/null +++ b/src/crystal/properties.cr @@ -0,0 +1,90 @@ +# Macro helpers to implement the getter and property macros on `Object`. + +module Crystal + {% for prefixes in { {"", "", "@", "#"}, {"class_", "self.", "@@", "."} } %} + {% + macro_prefix = prefixes[0].id + method_prefix = prefixes[1].id + var_prefix = prefixes[2].id + doc_prefix = prefixes[3] + %} + + # :nodoc: + macro def_{{macro_prefix}}var(name, nilable) + \{% if name.is_a?(TypeDeclaration) %} + \{% if nilable %} + {{var_prefix}}\{{name.var.id}} : \{{name.type}}? \{% if name.value %} = \{{name.value}} \{% end %} + \{% else %} + {{var_prefix}}\{{name}} + \{% end %} + \{% elsif name.is_a?(Assign) %} + {{var_prefix}}\{{name}} + \{% end %} + end + + {% for suffix in {"", "?"} %} + # :nodoc: + macro def_{{macro_prefix}}getter{{suffix.id}}(name, &block) + \{% if name.is_a?(TypeDeclaration) %} + \{% var_name = name.var.id %} + \{% type = name.type %} + \{% elsif name.is_a?(Assign) %} + \{% var_name = name.target %} + \{% type = nil %} + \{% else %} + \{% var_name = name.id %} + \{% type = nil %} + \{% end %} + + def {{method_prefix}}\{{var_name}}{{suffix.id}} \{% if type %} : \{{type}} \{% end %} + \{% if block %} + if (\%value = {{var_prefix}}\{{var_name}}).nil? + {{var_prefix}}\{{var_name}} = \{{yield}} + else + \%value + end + \{% else %} + {{var_prefix}}\{{var_name}} + \{% end %} + end + end + {% end %} + + # :nodoc: + macro def_{{macro_prefix}}getter!(klass, name) + \{% if name.is_a?(TypeDeclaration) %} + \{% var_name = name.var.id %} + \{% type = name.type %} + \{% else %} + \{% var_name = name.id %} + \{% type = nil %} + \{% end %} + + def {{method_prefix}}\{{var_name}}? \{% if type %} : \{{type}}? \{% end %} + {{var_prefix}}\{{var_name}} + end + + def {{method_prefix}}\{{var_name}} \{% if type %} : \{{type}} \{% end %} + if (%value = {{var_prefix}}\{{var_name}}).nil? + ::raise ::NilAssertionError.new(\{{"#{klass.id}#{{{doc_prefix}}.id}#{var_name} cannot be nil"}}) + else + %value + end + end + end + + # :nodoc: + macro def_{{macro_prefix}}setter(name) + \{% if name.is_a?(TypeDeclaration) %} + def {{method_prefix}}\{{name.var.id}}=({{var_prefix}}\{{name.var.id}} : \{{name.type}}) + end + \{% elsif name.is_a?(Assign) %} + def {{method_prefix}}\{{name.target.id}}=({{var_prefix}}\{{name.target.id}}) + end + \{% else %} + def {{method_prefix}}\{{name.id}}=({{var_prefix}}\{{name.id}}) + end + \{% end %} + end + {% end %} +end diff --git a/src/object.cr b/src/object.cr index 4443eaec3916..31678f943582 100644 --- a/src/object.cr +++ b/src/object.cr @@ -1,3 +1,5 @@ +require "crystal/properties" + # `Object` is the base type of all Crystal objects. class Object # Returns `true` if this object is equal to *other*. @@ -324,12 +326,11 @@ class Object pointerof(x).as(T*).value end - {% for prefixes in { {"", "", "@", "#"}, {"class_", "self.", "@@", "."} } %} + {% for prefixes in { {"", "", "@"}, {"class_", "self.", "@@"} } %} {% macro_prefix = prefixes[0].id method_prefix = prefixes[1].id var_prefix = prefixes[2].id - doc_prefix = prefixes[3].id %} # Defines getter methods for each of the given arguments. @@ -446,140 +447,10 @@ class Object # end # ``` macro {{macro_prefix}}getter(*names, &block) - \{% if block %} - \{% if names.size != 1 %} - \{{ raise "Only one argument can be passed to `getter` with a block" }} - \{% end %} - - \{% name = names[0] %} - - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name.var.id}} : \{{name.type}}? - - def {{method_prefix}}\{{name.var.id}} : \{{name.type}} - if (%value = {{var_prefix}}\{{name.var.id}}).nil? - {{var_prefix}}\{{name.var.id}} = \{{yield}} - else - %value - end - end - \{% else %} - def {{method_prefix}}\{{name.id}} - if (%value = {{var_prefix}}\{{name.id}}).nil? - {{var_prefix}}\{{name.id}} = \{{yield}} - else - %value - end - end - \{% end %} - \{% else %} - \{% for name in names %} - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.var.id}} : \{{name.type}} - {{var_prefix}}\{{name.var.id}} - end - \{% elsif name.is_a?(Assign) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.target.id}} - {{var_prefix}}\{{name.target.id}} - end - \{% else %} - def {{method_prefix}}\{{name.id}} - {{var_prefix}}\{{name.id}} - end - \{% end %} - \{% end %} - \{% end %} - end - - # Defines raise-on-nil and nilable getter methods for each of the given arguments. - # - # Writing: - # - # ``` - # class Person - # {{macro_prefix}}getter! name - # end - # ``` - # - # Is the same as writing: - # - # ``` - # class Person - # def {{method_prefix}}name? - # {{var_prefix}}name - # end - # - # def {{method_prefix}}name - # {{var_prefix}}name.not_nil! - # end - # end - # ``` - # - # The arguments can be string literals, symbol literals or plain names: - # - # ``` - # class Person - # {{macro_prefix}}getter! :name, "age" - # end - # ``` - # - # If a type declaration is given, a variable with that name - # is declared with that type, as nilable. - # - # ``` - # class Person - # {{macro_prefix}}getter! name : String - # end - # ``` - # - # is the same as writing: - # - # ``` - # class Person - # {{var_prefix}}name : String? - # - # def {{method_prefix}}name? - # {{var_prefix}}name - # end - # - # def {{method_prefix}}name - # {{var_prefix}}name.not_nil! - # end - # end - # ``` - macro {{macro_prefix}}getter!(*names) - \{% for name in names %} - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name}}? - - def {{method_prefix}}\{{name.var.id}}? : \{{name.type}}? - {{var_prefix}}\{{name.var.id}} - end - - def {{method_prefix}}\{{name.var.id}} : \{{name.type}} - if (%value = {{var_prefix}}\{{name.var.id}}).nil? - ::raise ::NilAssertionError.new("\{{@type}}\{{"{{doc_prefix}}".id}}\{{name.var.id}} cannot be nil") - else - %value - end - end - \{% else %} - def {{method_prefix}}\{{name.id}}? - {{var_prefix}}\{{name.id}} - end - - def {{method_prefix}}\{{name.id}} - if (%value = {{var_prefix}}\{{name.id}}).nil? - ::raise ::NilAssertionError.new("\{{@type}}\{{"{{doc_prefix}}".id}}\{{name.id}} cannot be nil") - else - %value - end - end - \{% end %} + \{% raise "Only one argument can be passed to `{{macro_prefix}}getter` with a block" if block && names.size > 1 %} + \{% for name, index in names %} + ::Crystal.def_{{macro_prefix}}var(\{{name}}, \{{!!block}}) + ::Crystal.def_{{macro_prefix}}getter(\{{name}}) \{{ block }} \{% end %} end @@ -673,66 +544,24 @@ class Object # end # ``` # - # If a block is given to the macro, a getter is generated - # with a variable that is lazily initialized with - # the block's contents, for examples see `#{{macro_prefix}}getter`. + # If a block is given to the macro, a getter is generated with a variable + # that is lazily initialized with the block's contents, for examples see + # `#{{macro_prefix}}getter`. macro {{macro_prefix}}getter?(*names, &block) - \{% if block %} - \{% if names.size != 1 %} - \{{ raise "Only one argument can be passed to `getter?` with a block" }} - \{% end %} - - \{% name = names[0] %} - - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name.var.id}} : \{{name.type}}? - - def {{method_prefix}}\{{name.var.id}}? : \{{name.type}} - if (%value = {{var_prefix}}\{{name.var.id}}).nil? - {{var_prefix}}\{{name.var.id}} = \{{yield}} - else - %value - end - end - \{% else %} - def {{method_prefix}}\{{name.id}}? - if (%value = {{var_prefix}}\{{name.id}}).nil? - {{var_prefix}}\{{name.id}} = \{{yield}} - else - %value - end - end - \{% end %} - \{% else %} - \{% for name in names %} - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.var.id}}? : \{{name.type}} - {{var_prefix}}\{{name.var.id}} - end - \{% elsif name.is_a?(Assign) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.target.id}}? - {{var_prefix}}\{{name.target.id}} - end - \{% else %} - def {{method_prefix}}\{{name.id}}? - {{var_prefix}}\{{name.id}} - end - \{% end %} - \{% end %} + \{% raise "Only one argument can be passed to `{{macro_prefix}}getter?` with a block" if block && names.size > 1 %} + \{% for name, index in names %} + ::Crystal.def_{{macro_prefix}}var(\{{name}}, \{{!!block}}) + ::Crystal.def_{{macro_prefix}}getter?(\{{name}}) \{{block}} \{% end %} end - # Defines setter methods for each of the given arguments. + # Defines property methods for each of the given arguments. # # Writing: # # ``` # class Person - # {{macro_prefix}}setter name + # {{macro_prefix}}property name # end # ``` # @@ -742,6 +571,10 @@ class Object # class Person # def {{method_prefix}}name=({{var_prefix}}name) # end + # + # def {{method_prefix}}name + # {{var_prefix}}name + # end # end # ``` # @@ -749,7 +582,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}setter :name, "age" + # {{macro_prefix}}property :name, "age" # end # ``` # @@ -758,17 +591,21 @@ class Object # # ``` # class Person - # {{macro_prefix}}setter name : String + # {{macro_prefix}}property name : String # end # ``` # - # is the same as writing: + # Is the same as writing: # # ``` # class Person # {{var_prefix}}name : String # - # def {{method_prefix}}name=({{var_prefix}}name : String) + # def {{method_prefix}}name=({{var_prefix}}name) + # end + # + # def {{method_prefix}}name + # {{var_prefix}}name # end # end # ``` @@ -777,7 +614,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}setter name : String = "John Doe" + # {{macro_prefix}}property name : String = "John Doe" # end # ``` # @@ -789,6 +626,10 @@ class Object # # def {{method_prefix}}name=({{var_prefix}}name : String) # end + # + # def {{method_prefix}}name + # {{var_prefix}}name + # end # end # ``` # @@ -797,7 +638,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}setter name = "John Doe" + # {{macro_prefix}}property name = "John Doe" # end # ``` # @@ -807,36 +648,57 @@ class Object # class Person # {{var_prefix}}name = "John Doe" # - # def {{method_prefix}}name=({{var_prefix}}name) + # def {{method_prefix}}name=({{var_prefix}}name : String) + # end + # + # def {{method_prefix}}name + # {{var_prefix}}name # end # end # ``` - macro {{macro_prefix}}setter(*names) - \{% for name in names %} - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.var.id}}=({{var_prefix}}\{{name.var.id}} : \{{name.type}}) - end - \{% elsif name.is_a?(Assign) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.target.id}}=({{var_prefix}}\{{name.target.id}}) - end - \{% else %} - def {{method_prefix}}\{{name.id}}=({{var_prefix}}\{{name.id}}) - end - \{% end %} + # + # If a block is given to the macro, a property is generated + # with a variable that is lazily initialized with + # the block's contents: + # + # ``` + # class Person + # {{macro_prefix}}property(birth_date) { Time.local } + # end + # ``` + # + # Is the same as writing: + # + # ``` + # class Person + # def {{method_prefix}}birth_date + # if (value = {{var_prefix}}birth_date).nil? + # {{var_prefix}}birth_date = Time.local + # else + # value + # end + # end + # + # def {{method_prefix}}birth_date=({{var_prefix}}birth_date) + # end + # end + # ``` + macro {{macro_prefix}}property(*names, &block) + \{% raise "Only one argument can be passed to `{{macro_prefix}}property` with a block" if block && names.size > 1 %} + \{% for name, index in names %} + ::Crystal.def_{{macro_prefix}}var(\{{name}}, \{{!!block}}) + ::Crystal.def_{{macro_prefix}}getter(\{{name}}) \{{block}} + ::Crystal.def_{{macro_prefix}}setter(\{{name}}) \{% end %} end - # Defines property methods for each of the given arguments. + # Defines query property methods for each of the given arguments. # # Writing: # # ``` # class Person - # {{macro_prefix}}property name + # {{macro_prefix}}property? happy # end # ``` # @@ -844,11 +706,11 @@ class Object # # ``` # class Person - # def {{method_prefix}}name=({{var_prefix}}name) + # def {{method_prefix}}happy=({{var_prefix}}happy) # end # - # def {{method_prefix}}name - # {{var_prefix}}name + # def {{method_prefix}}happy? + # {{var_prefix}}happy # end # end # ``` @@ -857,7 +719,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}property :name, "age" + # {{macro_prefix}}property? :happy, "famous" # end # ``` # @@ -866,7 +728,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}property name : String + # {{macro_prefix}}property? happy : Bool # end # ``` # @@ -874,13 +736,13 @@ class Object # # ``` # class Person - # {{var_prefix}}name : String + # {{var_prefix}}happy : Bool # - # def {{method_prefix}}name=({{var_prefix}}name) + # def {{method_prefix}}happy=({{var_prefix}}happy : Bool) # end # - # def {{method_prefix}}name - # {{var_prefix}}name + # def {{method_prefix}}happy? : Bool + # {{var_prefix}}happy # end # end # ``` @@ -889,7 +751,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}property name : String = "John Doe" + # {{macro_prefix}}property? happy : Bool = true # end # ``` # @@ -897,13 +759,13 @@ class Object # # ``` # class Person - # {{var_prefix}}name : String = "John Doe" + # {{var_prefix}}happy : Bool = true # - # def {{method_prefix}}name=({{var_prefix}}name : String) + # def {{method_prefix}}happy=({{var_prefix}}happy : Bool) # end # - # def {{method_prefix}}name - # {{var_prefix}}name + # def {{method_prefix}}happy? : Bool + # {{var_prefix}}happy # end # end # ``` @@ -913,7 +775,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}property name = "John Doe" + # {{macro_prefix}}property? happy = true # end # ``` # @@ -921,24 +783,36 @@ class Object # # ``` # class Person - # {{var_prefix}}name = "John Doe" + # {{var_prefix}}happy = true # - # def {{method_prefix}}name=({{var_prefix}}name : String) + # def {{method_prefix}}happy=({{var_prefix}}happy) # end # - # def {{method_prefix}}name - # {{var_prefix}}name + # def {{method_prefix}}happy? + # {{var_prefix}}happy # end # end # ``` # # If a block is given to the macro, a property is generated # with a variable that is lazily initialized with - # the block's contents: + # the block's contents, for examples see `#{{macro_prefix}}property`. + macro {{macro_prefix}}property?(*names, &block) + \{% raise "Only one argument can be passed to `{{macro_prefix}}property?` with a block" if block && names.size > 1 %} + \{% for name, index in names %} + ::Crystal.def_{{macro_prefix}}var(\{{name}}, \{{!!block}}) + ::Crystal.def_{{macro_prefix}}getter?(\{{name}}) \{{block}} + ::Crystal.def_{{macro_prefix}}setter(\{{name}}) + \{% end %} + end + + # Defines raise-on-nil and nilable getter methods for each of the given arguments. + # + # Writing: # # ``` # class Person - # {{macro_prefix}}property(birth_date) { Time.local } + # {{macro_prefix}}getter! name # end # ``` # @@ -946,80 +820,52 @@ class Object # # ``` # class Person - # def {{method_prefix}}birth_date - # if (value = {{var_prefix}}birth_date).nil? - # {{var_prefix}}birth_date = Time.local - # else - # value - # end + # def {{method_prefix}}name? + # {{var_prefix}}name # end # - # def {{method_prefix}}birth_date=({{var_prefix}}birth_date) + # def {{method_prefix}}name + # {{var_prefix}}name.not_nil! # end # end # ``` - macro {{macro_prefix}}property(*names, &block) - \{% if block %} - \{% if names.size != 1 %} - \{{ raise "Only one argument can be passed to `property` with a block" }} - \{% end %} - - \{% name = names[0] %} - - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name.var.id}} : \{{name.type}}? - - def {{method_prefix}}\{{name.var.id}} : \{{name.type}} - if (%value = {{var_prefix}}\{{name.var.id}}).nil? - {{var_prefix}}\{{name.var.id}} = \{{yield}} - else - %value - end - end - - def {{method_prefix}}\{{name.var.id}}=({{var_prefix}}\{{name.var.id}} : \{{name.type}}) - end - \{% else %} - def {{method_prefix}}\{{name.id}} - if (%value = {{var_prefix}}\{{name.id}}).nil? - {{var_prefix}}\{{name.id}} = \{{yield}} - else - %value - end - end - - def {{method_prefix}}\{{name.id}}=({{var_prefix}}\{{name.id}}) - end - \{% end %} - \{% else %} - \{% for name in names %} - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.var.id}} : \{{name.type}} - {{var_prefix}}\{{name.var.id}} - end - - def {{method_prefix}}\{{name.var.id}}=({{var_prefix}}\{{name.var.id}} : \{{name.type}}) - end - \{% elsif name.is_a?(Assign) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.target.id}} - {{var_prefix}}\{{name.target.id}} - end - - def {{method_prefix}}\{{name.target.id}}=({{var_prefix}}\{{name.target.id}}) - end - \{% else %} - def {{method_prefix}}\{{name.id}} - {{var_prefix}}\{{name.id}} - end - - def {{method_prefix}}\{{name.id}}=({{var_prefix}}\{{name.id}}) - end - \{% end %} - \{% end %} + # + # The arguments can be string literals, symbol literals or plain names: + # + # ``` + # class Person + # {{macro_prefix}}getter! :name, "age" + # end + # ``` + # + # If a type declaration is given, a variable with that name + # is declared with that type, as nilable. + # + # ``` + # class Person + # {{macro_prefix}}getter! name : String + # end + # ``` + # + # is the same as writing: + # + # ``` + # class Person + # {{var_prefix}}name : String? + # + # def {{method_prefix}}name? + # {{var_prefix}}name + # end + # + # def {{method_prefix}}name + # {{var_prefix}}name.not_nil! + # end + # end + # ``` + macro {{macro_prefix}}getter!(*names) + \{% for name in names %} + ::Crystal.def_{{macro_prefix}}var(\{{name}}, true) + ::Crystal.def_{{macro_prefix}}getter!(\{{@type}}, \{{name}}) \{% end %} end @@ -1086,26 +932,20 @@ class Object # end # ``` macro {{macro_prefix}}property!(*names) - {{macro_prefix}}getter! \{{names.splat}} - \{% for name in names %} - \{% if name.is_a?(TypeDeclaration) %} - def {{method_prefix}}\{{name.var.id}}=({{var_prefix}}\{{name.var.id}} : \{{name.type}}) - end - \{% else %} - def {{method_prefix}}\{{name.id}}=({{var_prefix}}\{{name.id}}) - end - \{% end %} + ::Crystal.def_{{macro_prefix}}var(\{{name}}, true) + ::Crystal.def_{{macro_prefix}}getter!(\{{@type}}, \{{name}}) + ::Crystal.def_{{macro_prefix}}setter(\{{name}}) \{% end %} end - # Defines query property methods for each of the given arguments. + # Defines setter methods for each of the given arguments. # # Writing: # # ``` # class Person - # {{macro_prefix}}property? happy + # {{macro_prefix}}setter name # end # ``` # @@ -1113,11 +953,7 @@ class Object # # ``` # class Person - # def {{method_prefix}}happy=({{var_prefix}}happy) - # end - # - # def {{method_prefix}}happy? - # {{var_prefix}}happy + # def {{method_prefix}}name=({{var_prefix}}name) # end # end # ``` @@ -1126,7 +962,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}property? :happy, "famous" + # {{macro_prefix}}setter :name, "age" # end # ``` # @@ -1135,21 +971,17 @@ class Object # # ``` # class Person - # {{macro_prefix}}property? happy : Bool + # {{macro_prefix}}setter name : String # end # ``` # - # Is the same as writing: + # is the same as writing: # # ``` # class Person - # {{var_prefix}}happy : Bool - # - # def {{method_prefix}}happy=({{var_prefix}}happy : Bool) - # end + # {{var_prefix}}name : String # - # def {{method_prefix}}happy? : Bool - # {{var_prefix}}happy + # def {{method_prefix}}name=({{var_prefix}}name : String) # end # end # ``` @@ -1158,7 +990,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}property? happy : Bool = true + # {{macro_prefix}}setter name : String = "John Doe" # end # ``` # @@ -1166,13 +998,9 @@ class Object # # ``` # class Person - # {{var_prefix}}happy : Bool = true - # - # def {{method_prefix}}happy=({{var_prefix}}happy : Bool) - # end + # {{var_prefix}}name : String = "John Doe" # - # def {{method_prefix}}happy? : Bool - # {{var_prefix}}happy + # def {{method_prefix}}name=({{var_prefix}}name : String) # end # end # ``` @@ -1182,7 +1010,7 @@ class Object # # ``` # class Person - # {{macro_prefix}}property? happy = true + # {{macro_prefix}}setter name = "John Doe" # end # ``` # @@ -1190,82 +1018,16 @@ class Object # # ``` # class Person - # {{var_prefix}}happy = true - # - # def {{method_prefix}}happy=({{var_prefix}}happy) - # end + # {{var_prefix}}name = "John Doe" # - # def {{method_prefix}}happy? - # {{var_prefix}}happy + # def {{method_prefix}}name=({{var_prefix}}name) # end # end # ``` - # - # If a block is given to the macro, a property is generated - # with a variable that is lazily initialized with - # the block's contents, for examples see `#{{macro_prefix}}property`. - macro {{macro_prefix}}property?(*names, &block) - \{% if block %} - \{% if names.size != 1 %} - \{{ raise "Only one argument can be passed to `property?` with a block" }} - \{% end %} - - \{% name = names[0] %} - - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name.var.id}} : \{{name.type}}? - - def {{method_prefix}}\{{name.var.id}}? : \{{name.type}} - if (%value = {{var_prefix}}\{{name.var.id}}).nil? - {{var_prefix}}\{{name.var.id}} = \{{yield}} - else - %value - end - end - - def {{method_prefix}}\{{name.var.id}}=({{var_prefix}}\{{name.var.id}} : \{{name.type}}) - end - \{% else %} - def {{method_prefix}}\{{name.id}}? - if (%value = {{var_prefix}}\{{name.id}}).nil? - {{var_prefix}}\{{name.id}} = \{{yield}} - else - %value - end - end - - def {{method_prefix}}\{{name.id}}=({{var_prefix}}\{{name.id}}) - end - \{% end %} - \{% else %} - \{% for name in names %} - \{% if name.is_a?(TypeDeclaration) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.var.id}}? : \{{name.type}} - {{var_prefix}}\{{name.var.id}} - end - - def {{method_prefix}}\{{name.var.id}}=({{var_prefix}}\{{name.var.id}} : \{{name.type}}) - end - \{% elsif name.is_a?(Assign) %} - {{var_prefix}}\{{name}} - - def {{method_prefix}}\{{name.target.id}}? - {{var_prefix}}\{{name.target.id}} - end - - def {{method_prefix}}\{{name.target.id}}=({{var_prefix}}\{{name.target.id}}) - end - \{% else %} - def {{method_prefix}}\{{name.id}}? - {{var_prefix}}\{{name.id}} - end - - def {{method_prefix}}\{{name.id}}=({{var_prefix}}\{{name.id}}) - end - \{% end %} - \{% end %} + macro {{macro_prefix}}setter(*names) + \{% for name in names %} + ::Crystal.def_{{macro_prefix}}var(\{{name}}, false) + ::Crystal.def_{{macro_prefix}}setter(\{{name}}) \{% end %} end {% end %}