Class: Norikra::Typedef

Inherits:
Object
  • Object
show all
Defined in:
lib/norikra/typedef.rb

Overview

Typedef is

* known field list of target (and these are optional or not), and container fields
* known field-set list of a target
* base set of a target

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fields = nil) ⇒ Typedef

Returns a new instance of Typedef.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/norikra/typedef.rb', line 16

def initialize(fields=nil)
  @container_fields = {}

  if fields && !fields.empty?
    given_set = FieldSet.new(fields, false) # default_optional=false, but chained access fields are always optional
    @fields = given_set.fields.dup
    base_fields = {}
    @fields.values.each do |field|
      if !field.optional?
        base_fields[field.name] = field
      elsif field.chained_access?
        cname = field.container_name
        @container_fields[cname] = Norikra::Field.new(cname, field.container_type, true)
      end
    end
    @baseset = FieldSet.new(base_fields, false)
  else
    @baseset = nil
    @fields = {}
  end

  @waiting_fields = []

  @queryfieldsets = []
  @datafieldsets = []

  @set_map = {} # FieldSet.field_names_key(data_fieldset, fieldset) => data_fieldset

  @mutex = Mutex.new
end

Instance Attribute Details

#basesetObject

Returns the value of attribute baseset.



14
15
16
# File 'lib/norikra/typedef.rb', line 14

def baseset
  @baseset
end

#container_fieldsObject

Returns the value of attribute container_fields.



14
15
16
# File 'lib/norikra/typedef.rb', line 14

def container_fields
  @container_fields
end

#datafieldsetsObject

Returns the value of attribute datafieldsets.



14
15
16
# File 'lib/norikra/typedef.rb', line 14

def datafieldsets
  @datafieldsets
end

#fieldsObject

Returns the value of attribute fields.



14
15
16
# File 'lib/norikra/typedef.rb', line 14

def fields
  @fields
end

#queryfieldsetsObject

Returns the value of attribute queryfieldsets.



14
15
16
# File 'lib/norikra/typedef.rb', line 14

def queryfieldsets
  @queryfieldsets
end

#waiting_fieldsObject

Returns the value of attribute waiting_fields.



14
15
16
# File 'lib/norikra/typedef.rb', line 14

def waiting_fields
  @waiting_fields
end

Instance Method Details

#activate(fieldset) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/norikra/typedef.rb', line 57

def activate(fieldset)
  @mutex.synchronize do
    set = fieldset.rebind(false) # base fieldset rebinding must not update event_type_name
    fieldset.fields.dup.each do |fieldname, field|
      set.fields[fieldname] = field.dup(false)
    end
    @baseset = set
    @baseset.fields.each do |name,f|
      @waiting_fields.delete(name) if @waiting_fields.include?(name)
    end
    @fields = @baseset.fields.merge(@fields)
  end
end

#consistent?(fieldset) ⇒ Boolean

Returns:

  • (Boolean)


88
89
90
91
92
93
# File 'lib/norikra/typedef.rb', line 88

def consistent?(fieldset)
  fields = fieldset.fields
  @baseset.subset?(fieldset) &&
    @fields.values.select{|f| !f.optional? }.reduce(true){|r,f| r && fields.has_key?(f.name) && fields[f.name].type == f.type} &&
    fields.values.reduce(true){|r,f| r && (!@fields.has_key?(f.name) || @fields[f.name].type == f.type)}
end

#dumpObject

to cli display



240
241
242
243
244
245
246
247
248
249
# File 'lib/norikra/typedef.rb', line 240

def dump # to cli display
  fields = {}
  @fields.each do |key,field|
    fields[key.to_sym] = field.to_hash(true) unless field.chained_access?
  end
  @container_fields.each do |key, field|
    fields[key.to_sym] = field.to_hash(true)
  end
  fields
end

#dump_allObject



232
233
234
235
236
237
238
# File 'lib/norikra/typedef.rb', line 232

def dump_all
  fields = {}
  @fields.each do |key,field|
    fields[field.name.to_sym] = field.to_hash(true)
  end
  fields
end

#field_defined?(list) ⇒ Boolean

Returns:

  • (Boolean)


47
48
49
50
51
# File 'lib/norikra/typedef.rb', line 47

def field_defined?(list)
  # used for only queries: TypedefManager#ready?(query) and TypedefManager#generate_field_mapping(query)
  #  be not needed to think about containers
  list.reduce(true){|r,f| r && @fields[f]}
end

#lazy?Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/norikra/typedef.rb', line 53

def lazy?
  @baseset.nil?
end

#pop(level, fieldset) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/norikra/typedef.rb', line 140

def pop(level, fieldset)
  @mutex.synchronize do
    case level
    when :base
      raise RuntimeError, "BUG: pop of base fieldset is nonsense (typedef deletion?)"
    when :query
      @queryfieldsets.delete(fieldset) if @queryfieldsets.include?(fieldset)
    when :data
      raise RuntimeError, "BUG: pop of data fieldset is nonsense"
    else
      raise ArgumentError, "unknown level #{level}"
    end
  end
  true
end

#push(level, fieldset) ⇒ Object



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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/norikra/typedef.rb', line 95

def push(level, fieldset)
  unless self.consistent?(fieldset)
    warn "fieldset mismatch", :self => self, :with => fieldset
    raise Norikra::ArgumentError, "field definition mismatch with already defined fields"
  end

  @mutex.synchronize do
    case level
    when :base
      unless @baseset.object_id == fieldset.object_id
        raise RuntimeError, "baseset mismatch"
      end
    when :query
      unless @queryfieldsets.include?(fieldset)
        @queryfieldsets.push(fieldset)

        fieldset.fields.each do |fieldname,field|
          @waiting_fields.delete(fieldname) if @waiting_fields.include?(fieldname)
          @fields[fieldname] = field.dup(true) unless @fields[fieldname]
        end
      end
    when :data
      unless @datafieldsets.include?(fieldset)
        @datafieldsets.push(fieldset)
        @set_map[fieldset.field_names_key] = fieldset

        fieldset.fields.each do |fieldname,field|
          if @waiting_fields.include?(fieldname)
            @waiting_fields.delete(fieldname)
          end
          unless @fields[fieldname]
            @fields[fieldname] = field.dup(true)
            if field.chained_access? && !@container_fields[field.container_name]
              @container_fields[field.container_name] = Norikra::Field.new(field.container_name, field.container_type, true)
            end
          end
        end
      end
    else
      raise ArgumentError, "unknown level #{level}"
    end
  end
  true
end

#refer(data, strict = false) ⇒ Object



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/norikra/typedef.rb', line 215

def refer(data, strict=false)
  field_names_key = FieldSet.field_names_key(data, self, strict, @waiting_fields)
  return @set_map[field_names_key] if @set_map.has_key?(field_names_key)

  guessed = self.simple_guess(data, optional: false, strict: strict)
  guessed_fields = guessed.fields
  @fields.each do |key,field|
    if guessed_fields.has_key?(key)
      guessed_fields[key].type = field.type if guessed_fields[key].type != field.type
      guessed_fields[key].optional = field.optional if guessed_fields[key].optional != field.optional
    else
      guessed_fields[key] = field unless field.optional?
    end
  end
  guessed.update_summary #=> guessed
end

#replace(level, old_fieldset, fieldset) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/norikra/typedef.rb', line 156

def replace(level, old_fieldset, fieldset)
  unless self.consistent?(fieldset)
    warn "fieldset mismatch", :self => self, :with => fieldset
    raise Norikra::ArgumentError, "field definition mismatch with already defined fields"
  end
  if level != :data
    raise ArgumentError, "invalid argument, fieldset replace should be called for :data"
  end
  if old_fieldset.field_names_key != fieldset.field_names_key
    raise ArgumentError, "try to replace different field name sets"
  end
  @mutex.synchronize do
    @datafieldsets.delete(old_fieldset)
    @set_map[fieldset.field_names_key] = fieldset
    @datafieldsets.push(fieldset)
  end
  true
end

#reserve(fieldname, type, optional = true) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/norikra/typedef.rb', line 71

def reserve(fieldname, type, optional=true)
  fieldname = fieldname.to_s
  @mutex.synchronize do
    return false if @fields[fieldname]
    field = Norikra::Field.new(fieldname, type, optional)
    if @waiting_fields.include?(fieldname)
      @waiting_fields.delete(fieldname)
    end
    @fields[fieldname] = field
    if field.chained_access? && !@container_fields[field.container_name]
      container = Norikra::Field.new(field.container_name, field.container_type, true)
      @container_fields[field.container_name] = container
    end
  end
  true
end

#simple_guess(data, opts = {}) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/norikra/typedef.rb', line 175

def simple_guess(data, opts={})
  unless opts.has_key?(:optional)
    opts[:optional] = true
  end

  flatten_key_value_pairs = []

  data.each do |key,value|
    next if opts[:strict] && !(@fields.has_key?(key) || @waiting_fields.include?(key) || value.is_a?(Hash) || value.is_a?(Array))

    if value.is_a?(Hash) || value.is_a?(Array)
      next if opts[:baseset]

      Norikra::FieldSet.leaves(value).map{|chain| [key] + chain}.each do |chain|
        value = chain.pop
        key = Norikra::Field.regulate_key_chain(chain).join('.')
        next unless @fields.has_key?(key) || @waiting_fields.include?(key)
        flatten_key_value_pairs.push([key, value])
      end
    else
      flatten_key_value_pairs.push([key, value])
    end
  end

  mapping = Hash[
    flatten_key_value_pairs.map{|key,value|
      type = case value
             when TrueClass,FalseClass then 'boolean'
             when Integer then 'long'
             when Float   then 'double'
             else
               'string'
             end
      [key,type]
    }
  ]

  FieldSet.new(mapping, opts[:optional])
end