Class: Wrapture::ClassSpec
- Inherits:
-
Object
- Object
- Wrapture::ClassSpec
- Defined in:
- lib/wrapture/class_spec.rb
Overview
A description of a class, including its constants, functions, and other details.
Instance Attribute Summary collapse
-
#struct ⇒ Object
readonly
The underlying struct of this class.
Class Method Summary collapse
-
.effective_type(spec) ⇒ Object
Gives the effective type of the given class spec hash.
-
.normalize_spec_hash(spec) ⇒ Object
Normalizes a hash specification of a class.
Instance Method Summary collapse
-
#cast(instance, to, from = name) ⇒ Object
Returns a cast of an instance of this class with the provided name to the specified type.
-
#generate_wrappers ⇒ Object
Generates the wrapper class declaration and definition files.
-
#initialize(spec, scope: Scope.new) ⇒ ClassSpec
constructor
Creates a class spec based on the provided hash spec.
-
#name ⇒ Object
The name of the class.
-
#overloads?(parent_spec) ⇒ Boolean
True if this class overloads the given one.
-
#parent_name ⇒ Object
The name of the parent of this class, or nil if there is no parent.
-
#pointer_wrapper? ⇒ Boolean
Determines if this class is a wrapper for a struct pointer or not.
-
#struct_name ⇒ Object
The name of the equivalent struct of this class.
-
#this_struct ⇒ Object
Gives a code snippet that accesses the equivalent struct from within the class using the 'this' keyword.
-
#this_struct_pointer ⇒ Object
Gives a code snippet that accesses the equivalent struct pointer from within the class using the 'this' keyword.
-
#type(type) ⇒ Object
Returns the ClassSpec for the given type in this class's scope.
-
#type?(type) ⇒ Boolean
Returns true if the given type exists in this class's scope.
Constructor Details
#initialize(spec, scope: Scope.new) ⇒ ClassSpec
Creates a class spec based on the provided hash spec.
The scope can be provided if available.
The hash must have the following keys:
- name
the name of the class
- namespace
the namespace to put the class into
- equivalent-struct
a hash describing the struct this class wraps
The following keys are optional:
- doc
a string containing the documentation for this class
- constructors
a list of function specs that can create this class
- destructor
a function spec for the destructor of the class
- functions
a list of function specs
- constants
a list of constant specs
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 122 123 124 125 126 127 128 129 |
# File 'lib/wrapture/class_spec.rb', line 92 def initialize(spec, scope: Scope.new) @spec = Marshal.load(Marshal.dump(spec)) TemplateSpec.replace_all_uses(@spec, *scope.templates) @spec = ClassSpec.normalize_spec_hash(@spec) @struct = if @spec.key?(EQUIVALENT_STRUCT_KEYWORD) StructSpec.new(@spec[EQUIVALENT_STRUCT_KEYWORD]) end @functions = @spec['constructors'].map do |constructor_spec| full_spec = constructor_spec.dup full_spec['name'] = @spec['name'] full_spec['params'] = constructor_spec['wrapped-function']['params'] FunctionSpec.new(full_spec, self, constructor: true) end if @spec.key?('destructor') destructor_spec = @spec['destructor'].dup destructor_spec['name'] = "~#{@spec['name']}" @functions << FunctionSpec.new(destructor_spec, self, destructor: true) end @spec['functions'].each do |function_spec| @functions << FunctionSpec.new(function_spec, self) end @constants = @spec['constants'].map do |constant_spec| ConstantSpec.new(constant_spec) end @doc = @spec.key?('doc') ? Comment.new(@spec['doc']) : nil scope << self @scope = scope end |
Instance Attribute Details
#struct ⇒ Object (readonly)
The underlying struct of this class.
75 76 77 |
# File 'lib/wrapture/class_spec.rb', line 75 def struct @struct end |
Class Method Details
.effective_type(spec) ⇒ Object
Gives the effective type of the given class spec hash.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/wrapture/class_spec.rb', line 54 def self.effective_type(spec) inferred_pointer_wrapper = spec['constructors'].any? do |func| func['wrapped-function']['return']['type'] == EQUIVALENT_POINTER_KEYWORD end if spec.key?('type') valid_types = %w[pointer struct] unless valid_types.include?(spec['type']) = "#{spec['type']} is not a valid class type" raise InvalidSpecKey.new(, valid_keys: valid_types) end spec['type'] elsif inferred_pointer_wrapper 'pointer' else 'struct' end end |
.normalize_spec_hash(spec) ⇒ Object
Normalizes a hash specification of a class. Normalization will check for things like invalid keys, duplicate entries in include lists, and will set missing keys to their default values (for example, an empty list if no includes are given).
If this spec cannot be normalized, for example because it is invalid or it uses an unsupported version type, then an exception is raised.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/wrapture/class_spec.rb', line 32 def self.normalize_spec_hash(spec) raise NoNamespace unless spec.key?('namespace') raise MissingSpecKey, 'name key is required' unless spec.key?('name') Comment.validate_doc(spec['doc']) if spec.key?('doc') normalized = spec.dup normalized.default = [] normalized['version'] = Wrapture.spec_version(spec) normalized['includes'] = Wrapture.normalize_includes(spec['includes']) normalized['type'] = ClassSpec.effective_type(normalized) if spec.key?('parent') includes = Wrapture.normalize_includes(spec['parent']['includes']) normalized['parent']['includes'] = includes end normalized end |
Instance Method Details
#cast(instance, to, from = name) ⇒ Object
Returns a cast of an instance of this class with the provided name to the specified type. Optionally the from parameter may hold the type of the instance, either a reference or a pointer.
134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/wrapture/class_spec.rb', line 134 def cast(instance, to, from = name) member_access = from.pointer? ? '->' : '.' struct = "struct #{@struct.name}" if [EQUIVALENT_STRUCT_KEYWORD, struct].include?(to) "#{'*' if pointer_wrapper?}#{instance}#{member_access}equivalent" elsif [EQUIVALENT_POINTER_KEYWORD, "#{struct} *"].include?(to) "#{'&' unless pointer_wrapper?}#{instance}#{member_access}equivalent" end end |
#generate_wrappers ⇒ Object
Generates the wrapper class declaration and definition files.
147 148 149 |
# File 'lib/wrapture/class_spec.rb', line 147 def generate_wrappers [generate_declaration_file, generate_definition_file] end |
#name ⇒ Object
The name of the class
152 153 154 |
# File 'lib/wrapture/class_spec.rb', line 152 def name @spec['name'] end |
#overloads?(parent_spec) ⇒ Boolean
True if this class overloads the given one. A class is considered an overload if its parent is the given class, it has the same equivalent struct name, and the equivalent struct has a set of rules. The overloaded class cannot have any rules in its equivalent struct, or it will not be overloaded.
161 162 163 164 165 166 167 |
# File 'lib/wrapture/class_spec.rb', line 161 def overloads?(parent_spec) return false unless parent_spec.struct&.rules&.empty? parent_spec.struct.name == struct_name && parent_spec.name == parent_name && !@struct.rules.empty? end |
#parent_name ⇒ Object
The name of the parent of this class, or nil if there is no parent.
170 171 172 |
# File 'lib/wrapture/class_spec.rb', line 170 def parent_name @spec['parent']['name'] if child? end |
#pointer_wrapper? ⇒ Boolean
Determines if this class is a wrapper for a struct pointer or not.
175 176 177 |
# File 'lib/wrapture/class_spec.rb', line 175 def pointer_wrapper? @spec['type'] == 'pointer' end |
#struct_name ⇒ Object
The name of the equivalent struct of this class.
180 181 182 |
# File 'lib/wrapture/class_spec.rb', line 180 def struct_name @struct.name end |
#this_struct ⇒ Object
Gives a code snippet that accesses the equivalent struct from within the class using the 'this' keyword.
186 187 188 189 190 191 192 |
# File 'lib/wrapture/class_spec.rb', line 186 def this_struct if pointer_wrapper? '*(this->equivalent)' else 'this->equivalent' end end |
#this_struct_pointer ⇒ Object
Gives a code snippet that accesses the equivalent struct pointer from within the class using the 'this' keyword.
196 197 198 |
# File 'lib/wrapture/class_spec.rb', line 196 def this_struct_pointer "#{'&' unless pointer_wrapper?}this->equivalent" end |
#type(type) ⇒ Object
Returns the ClassSpec for the given type in this class's scope.
201 202 203 |
# File 'lib/wrapture/class_spec.rb', line 201 def type(type) @scope.type(type) end |
#type?(type) ⇒ Boolean
Returns true if the given type exists in this class's scope.
206 207 208 |
# File 'lib/wrapture/class_spec.rb', line 206 def type?(type) @scope.type?(type) end |