4 # creates a new Struct-based class, takes the following
7 # :db - pre-created LWES::TypeDB object
8 # this is required unless :file is given
9 # :file - pathname to the ESF file,
10 # this is required unless :db is given
11 # :class - Ruby base class name, if the ESF file only has one
12 # event defined (besides MetaEventInfo), then specifying
13 # it is optional, otherwise it is required when multiple
14 # events are defined in the same ESF :file given above
15 # :parent - parent class or module, the default is 'Object' putting
16 # the new class in the global namespace.
17 # :name - event name if it differs from the Ruby base class name
18 # given (or inferred) above. For DRY-ness, you are
19 # recommended to keep your event names and Ruby class
20 # names in sync and not need this option.
21 # :skip - Array of field names to skip from the Event defininition
22 # entirely, these could include fields that are only
23 # implemented by the Listener. This may also be a
25 # :defaults - hash of default key -> value pairs to set at
28 def self.new(options, &block)
31 file = options[:file] or
32 raise ArgumentError, "TypeDB :db or ESF :file missing"
34 raise ArgumentError, "file #{file.inspect} not readable"
38 klass = options[:class] || begin
39 # make it easier to deal with single event files
40 events = (dump.keys - [ :MetaEventInfo ])
43 "multiple event defs available: #{events.inspect}\n" \
44 "pick one with :class"
48 name = options[:name] || klass
49 parent = options[:parent] || Object
50 event_def = dump[name.to_sym] or
51 raise RuntimeError, "#{name.inspect} not defined in #{file}"
53 # merge MetaEventInfo fields in
54 meta_event_info = dump[:MetaEventInfo]
55 alpha = proc { |a,b| a.first.to_s <=> b.first.to_s }
56 event_def = event_def.sort(&alpha)
58 seen = event_def.map { |(field, _)| field }
59 meta_event_info.sort(&alpha).each do |field_type|
60 seen.include?(field_type.first) or event_def << field_type
64 Array(options[:skip]).each do |x|
66 event_def.delete_if { |(f,_)| x =~ f.to_s }
68 if x.to_sym == :MetaEventInfo
69 meta_event_info.nil? and
70 raise RuntimeError, "MetaEventInfo not defined in #{file}"
71 meta_event_info.each do |(field,_)|
72 event_def.delete_if { |(f,_)| field == f }
75 event_def.delete_if { |(f,_)| f == x.to_sym }
80 tmp = ::Struct.new(*(event_def.map { |(field,_)| field }))
81 tmp = parent.const_set(klass, tmp)
82 tmp.const_set :TYPE_DB, db
83 tmp.const_set :NAME, name.to_s
84 ed = tmp.const_set :EVENT_DEF, {}
85 event_def.each { |(field,type)| ed[field] = type }
86 type_list = event_def.map { |(field,type)| [ field, field.to_s, type ] }
87 tmp.const_set :TYPE_LIST, type_list
89 defaults = options[:defaults] || {}
90 defaults = tmp.const_set :DEFAULTS, defaults.dup
91 tmp.class_eval(&block) if block_given?
93 # define a parent-level method, eval is faster than define_method
100 if Hash === (init = args.first)
102 DEFAULTS.merge(init).each_pair { |k,v| rv[k] = v }
106 DEFAULTS.each_pair { |k,v| rv[k] ||= v }