Class: Hamachi::Model

Inherits:
Hash
  • Object
show all
Defined in:
lib/hamachi/model.rb

Defined Under Namespace

Classes: EnumMatcher, ListMatcher, Matcher, NullableMatcher, PositiveMatcher, PositiveOrZeroMatcher

Constant Summary collapse

NULL =
Object.new
Boolean =
enum(true, false)
Timestamp =
Regexp.new(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\d\d\dZ$/)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(snapshot, options = {}) ⇒ Model

Returns a new instance of Model.



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/hamachi/model.rb', line 66

def initialize(snapshot, options = {})
  update(snapshot) unless options.fetch(:ignore_undeclared_fields, false)

  self.class.fields.each do |name, field|
    value = snapshot.fetch(name, field.default_value)
    self[name] = field.from_snapshot(value, options)
  end

  check_types if options.fetch(:check_types, true)
  freeze if options.fetch(:freeze, false)
end

Class Method Details

.define(&block) ⇒ Object

for anonymous inline models



143
144
145
# File 'lib/hamachi/model.rb', line 143

def self.define(&block) # for anonymous inline models
  Class.new Hamachi::Model, &block
end

.enum(*symbols) ⇒ Object

— Helper methods for type declarations ——————



154
155
156
# File 'lib/hamachi/model.rb', line 154

def self.enum(*symbols)
  EnumMatcher.new(symbols)
end

.field(name, options) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/hamachi/model.rb', line 118

def self.field(name, options)
  raise "expected #{name} to be undefined, got method" if method_defined?(name.to_sym)

  field = options.fetch(:type)
  field = Matcher.new(field) unless Matcher === field
  field.initialize_options(options).freeze
  self.fields[name.to_sym] = field

  class_eval %{
    def #{name}
      self[:#{name}]
    end
  }

  class_eval %{
    def #{name}=(value)
      field = self.class.fields[:#{name}]
      if not field === value
        raise "expected #{name} to be \#{field}, got \#{value.inspect}"
      end
      self[:#{name}] = value
    end
  }
end

.fieldsObject



114
115
116
# File 'lib/hamachi/model.rb', line 114

def self.fields
  @fields ||= {}
end

.from_json(str) ⇒ Object



86
87
88
89
# File 'lib/hamachi/model.rb', line 86

def self.from_json(str)
  snapshot = JSON.parse str, symbolize_names: true
  self.from_snapshot(snapshot, {})
end

.from_snapshot(snapshot, options = {}) ⇒ Object



78
79
80
81
82
83
84
# File 'lib/hamachi/model.rb', line 78

def self.from_snapshot(snapshot, options = {})
  return snapshot unless Hash === snapshot
  unless snapshot.keys.all? { |name| Symbol === name }
    raise "expected names to be symbols, got other"
  end
  self.new snapshot, options
end

.list(type) ⇒ Object



158
159
160
# File 'lib/hamachi/model.rb', line 158

def self.list(type)
  ListMatcher.new(type)
end

.model(&block) ⇒ Object



166
167
168
# File 'lib/hamachi/model.rb', line 166

def self.model(&block)
  Hamachi::Model.define(&block)
end

.nullable(type) ⇒ Object



162
163
164
# File 'lib/hamachi/model.rb', line 162

def self.nullable(type)
  NullableMatcher.new(type)
end

.positive(type) ⇒ Object



170
171
172
# File 'lib/hamachi/model.rb', line 170

def self.positive(type)
  PositiveMatcher.new(type)
end

.positive_or_zero(type) ⇒ Object



174
175
176
# File 'lib/hamachi/model.rb', line 174

def self.positive_or_zero(type)
  PositiveOrZeroMatcher.new(type)
end

.to_sObject



147
148
149
# File 'lib/hamachi/model.rb', line 147

def self.to_s
  name ? name : "model(#{fields.map { |name, field| "#{name}:#{field}"}.join(',')})"
end

Instance Method Details

#check_typesObject



91
92
93
94
95
96
97
# File 'lib/hamachi/model.rb', line 91

def check_types
  self.class.fields.each do |name, field|
    if not field === self[name]
      raise "expected #{name} to be #{field}, got #{self[name].inspect}"
    end
  end
end

#prune_default_valuesObject



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/hamachi/model.rb', line 99

def prune_default_values
  self.class.fields.each do |name, field|
    case value = self[name]
    when field.default_value
      self.delete(name)
    when Model
      value.prune_default_values
    when Array
      value.each { |each| each.prune_default_values if Model === each }
    end
  end

  return self
end