Class: TypedStruct
Overview
Like a Stuct, but automatically casts assignments to specific types.
Example:
class SomeRecord < TypedStruct["some_id:int amount:float name:string a,b,c:bool untyped_var"]
end
record = SomeRecord.new(69, 12348.871, "stringy", true, 1, "no", Object.new)
another_record = SomeRecord.new :amount=>"1.5", :name=>"Steve", :c=>"true", :a=>"disable", :untyped_var=>Ratio.new(1/2)
record.amount *= 3.141592653589793238462643383279
Recognized types, and what they get converted into:
<no type given> => Don't enforce a type -- any ruby object is allowed.
["str", "string"] => String
["sym", "symbol"] => Symbol
["int", "integer"] => Integer
["float"] => Float
["bigdecimal"] => BigDecimal
["hex"] => Integer
["date", "time", "datetime"] => DateTime (using DateTime.parse)
["timestamp", "unixtime"] => Time (using Time.at)
["bool", "boolean"] => Boolean, using the following rules:
false when: false, nil, 0, "0", "off", "no",
"false", "disabled", "disable"
true when: true, 1, "1", "on", "yes",
"true", "enabled", "enable"
Constant Summary collapse
- CONVERTERS =
A perhaps-too-clever table of { “typename” => convert_proc } mappings.
Hash[ *{ [:passthru]
Class Method Summary collapse
-
.[](specs) ⇒ Object
Initialize a new struct.
Instance Method Summary collapse
-
#initialize(*args) ⇒ TypedStruct
constructor
A new instance of TypedStruct.
Methods inherited from Struct
Constructor Details
#initialize(*args) ⇒ TypedStruct
Returns a new instance of TypedStruct.
123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/epitools/typed_struct.rb', line 123 def initialize(*args) if args.size == 1 and args.first.is_a? Hash opts = args.first else opts = members.zip(args) end if @@drop_unknown opts.each { |key,value| send "#{key}=", value if respond_to? "#{key}=" } else opts.each { |key,value| send "#{key}=", value } end end |
Class Method Details
.[](specs) ⇒ Object
Initialize a new struct.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/epitools/typed_struct.rb', line 66 def self.[](specs) wildcard = false drop_unknown = false # create [name,type] pairs pairs = specs.split.map do |spec| case spec when "*" wildcard = true next when "-" drop_unknown = true next end names, type = spec.split(":") names.split(",").map do |name| type ||= :passthru raise "Unknown type: #{type}" unless converter = CONVERTERS[type] [name.to_sym, converter] end end.compact.flatten(1) raise "Error: Can't specify both wildcard ('*') and drop unknown ('-')" if wildcard and drop_unknown # initialize the Struct struct = new(*pairs.transpose.first) # overload setter methods to call the proc pairs.each do |field, converter| next if converter == :passthru struct.send(:define_method, "#{field}=") do |val| self[field] = ( val and converter.call val ) end end if wildcard struct.class_eval do def method_missing(name, val=nil) if name =~ /^(.+)=$/ @extra_slots ||= {} @extra_slots[$1.to_sym] = val else @extra_slots && @extra_slots[name] end end end end struct.class_eval do @@drop_unknown = drop_unknown end struct end |