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.



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
46
47
48
49
# File 'lib/norikra/typedef.rb', line 17

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 = []

  # FieldSet.field_names_key(data_fieldset, fieldset) => data_fieldset
  ### field_names_key is built by keys w/ data, without null fields
  ### data_fieldset includes null fields
  @set_map = {}

  @mutex = Mutex.new
end

Instance Attribute Details

#basesetObject

Returns the value of attribute baseset.



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

def baseset
  @baseset
end

#container_fieldsObject

Returns the value of attribute container_fields.



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

def container_fields
  @container_fields
end

#datafieldsetsObject

Returns the value of attribute datafieldsets.



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

def datafieldsets
  @datafieldsets
end

#fieldsObject

Returns the value of attribute fields.



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

def fields
  @fields
end

#queryfieldsetsObject

Returns the value of attribute queryfieldsets.



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

def queryfieldsets
  @queryfieldsets
end

#waiting_fieldsObject

Returns the value of attribute waiting_fields.



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

def waiting_fields
  @waiting_fields
end

Instance Method Details

#activate(fieldset) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/norikra/typedef.rb', line 61

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)


92
93
94
95
96
97
# File 'lib/norikra/typedef.rb', line 92

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



245
246
247
248
249
250
251
252
253
254
# File 'lib/norikra/typedef.rb', line 245

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



237
238
239
240
241
242
243
# File 'lib/norikra/typedef.rb', line 237

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)


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

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)


57
58
59
# File 'lib/norikra/typedef.rb', line 57

def lazy?
  @baseset.nil?
end

#pop(level, fieldset) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/norikra/typedef.rb', line 144

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



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
139
140
141
142
# File 'lib/norikra/typedef.rb', line 99

def push(level, fieldset)
  unless self.consistent?(fieldset)
    warn "fieldset mismatch", receiver: 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



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/norikra/typedef.rb', line 220

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, 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



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/norikra/typedef.rb', line 160

def replace(level, old_fieldset, fieldset)
  unless self.consistent?(fieldset)
    warn "fieldset mismatch", receiver: 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



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/norikra/typedef.rb', line 75

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



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
214
215
216
217
218
# File 'lib/norikra/typedef.rb', line 179

def simple_guess(data, opts={})
  #### in typedef_manager
  # guessed = @typedefs[target].simple_guess(event, strict: false, baseset: true)

  #### in Typedef#refer
  # guessed = self.simple_guess(data, strict: strict)

  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 {type: 'boolean'}
             when Integer then {type: 'long'}
             when Float   then {type: 'double'}
             else {type: 'string'}
             end
      [key,type]
    }
  ]

  FieldSet.new(mapping, false) # in simple_guess, optional is always false
end