Class: RText::Language

Inherits:
Object
  • Object
show all
Defined in:
lib/rtext/language.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root_epackage, options = {}) ⇒ Language

Creates an RText language description for the metamodel described by root_epackage Valid options include:

:feature_provider
   a Proc which receives an EClass and should return a subset of this EClass's features
   this can be used to filter and/or reorder the features
   note that in most cases, this Proc will have to filter opposite references
   default: all features filtered using OppositeReferenceFilter 

:unlabled_arguments
   a Proc which receives an EClass and should return this EClass's feature names which are
   to be serialized without lables in the given order and before all labled arguments
   the features must also occur in :feature_provider if :feature_provider is provided
   if unlabled arguments are not part of the current class's features, they will be ignored
   default: no unlabled arguments

:unquoted_arguments
   a Proc which receives an EClass and should return this EClass's string typed attribute
   names which are to be serialized without quotes. input data my still be quoted.
   the serializer will take care to insert quotes if the data is not a valid identifier
   the features must also occur in :feature_provider if :feature_provider is provided
   default: no unquoted arguments

:labeled_containments
   a Proc which receives an EClass and should return the names of this EClass's containment 
   references which are to be serialized with a label.
   note that labels will always automatically be used when references can't be uniquely 
   derived from contained elements
   default: no additional labeled containments

:argument_format_provider
   a Proc which receives an EAttribute and should return a format specification string
   (in sprintf syntax) which will be used by the serializer for integers and floats.
   default: if not present or the proc returns nil, then #to_s is used

:reference_regexp  
   a Regexp which is used by the tokenizer for identifying references 
   it must only match at the beginning of a string, i.e. it should start with \A
   it must be built in a way that does not match other language constructs
   in particular it must not match identifiers (word characters not starting with a digit)
   identifiers can always be used where references are expected
   default: word characters separated by at least one slash (/) 

:identifier_provider
   a Proc which receives an element, its containing element, the feature through which the
   element is referenced and the index position of the reference within the feature's values.
   the latter 3 argumnets may be nil. it should return the element's identifier as a string.
   the identifier must be unique for the element unless "per_type_identifier" is set to true,
   in which case they must be unique for each element of the same type.
   identifiers may be relative to the given containing element, depending on the given
   feature and index position. in this case a globally unique 
   identifier must be resonstructed by the proc specified using the :reference_qualifier option.
   if the containing element is nil, the identifier returned must be globally unique.
   default: identifiers calculated by QualifiedNameProvider
            in this case options to QualifiedNameProvider may be provided and will be passed through

:per_type_identifier
   if set to true, identifiers may be reused for elements of different type
   default: false

:reference_qualifier
   a Proc which receives RGen unresolved references and either a FragmentedModel or a ModelFragment.
   it should modify the unresolved references' targetIdentifiers to make them globally unique.
   the Proc is called for each fragment after it as been loaded and for the overall model.
   this can be used to qualify context specific references returned by the identifier provider.
   default: no reference qualifier

:root_classes
   an Array of EClass objects representing classes which can be used on root level
   default: all classes which can't be contained by any class

:line_number_attribute
   the name of the attribute which will be used to associate the line number with a model element
   default: no line number

:file_name_attribute
   the name of the attribute which will be used to associate the file name with a model element
   default: no file name

:fragment_ref_attribute
   the name of the attribute which will be used to associate a model fragment with a model element

:comment_handler 
   a Proc which will be invoked when a new element has been instantiated. receives  
   the comment as a string, the comment kind (one of [:above, :eol, :unassociated]), the
   element and the environment to which the element has been added to.
   the environment may be nil.  it should add the comment to the element and 
   return true. if the element can take no comment, it should return false.
   default: no handling of comments 

:comment_provider
   a Proc which receives an element and should return this element's comment as a string or nil
   the Proc may also modify the element to remove information already part of the comment
   default: no comments

:annotation_handler
   a Proc which will be invoked when a new element has been instantiated. receives  
   the annotation as a string, the element and the environment to which the element has been added to.
   the environment may be nil. it may change the model or otherwise use the annotated information. 
   if the element can take no annotation, it should return false, otherwise true.
   default: no handling of annotations 

:annotation_provider
   a Proc which receives an element and should return this element's annotation as a string or nil.
   the Proc may also modify the element to remove information already part of the annotation.
   default: no annotations

:indent_string
   the string representing one indent, could be a tab or spaces
   default: 2 spaces

:command_name_provider
   a Proc which receives an EClass object and should return an RText command name
   default: class name

:backward_ref_attribute
   a Proc which receives an EClass object and should return the name of this class's
   feature which is used to represent backward references (i.e. for following the backward
   reference, the user must click on a value of this attribute)
   a value of nil means that the command name is used to follow the backward reference
   default: nil (command name)

:enable_generics
   if set to true, generics (<value>) are allowed, otherwise forbidden
   default: false


136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/rtext/language.rb', line 136

def initialize(root_epackage, options={})
  @root_epackage = root_epackage
  @feature_provider = options[:feature_provider] || 
    proc { |c| RGen::Serializer::OppositeReferenceFilter.call(c.eAllStructuralFeatures).
      reject{|f| f.derived} }
  @unlabled_arguments = options[:unlabled_arguments]
  @unquoted_arguments = options[:unquoted_arguments]
  @labeled_containments = options[:labeled_containments]
  @argument_format_provider = options[:argument_format_provider]
  @root_classes = options[:root_classes] || default_root_classes(root_epackage)
  command_name_provider = options[:command_name_provider] || proc{|c| c.name}
  setup_commands(root_epackage, command_name_provider)
  @reference_regexp = options[:reference_regexp] || /\A\w*(\/\w*)+/
  @identifier_provider = options[:identifier_provider] || 
    proc { |element, context, feature, index|
      @qualified_name_provider ||= RGen::Serializer::QualifiedNameProvider.new(options)
      name_attribute = options[:attribute_name] || "name"
      if element.is_a?(RGen::MetamodelBuilder::MMProxy) || element.respond_to?(name_attribute)
        @qualified_name_provider.identifier(element)
      else
        nil
      end
    }
  @reference_qualifier = options[:reference_qualifier] || proc{|urefs, model_or_fragment| }
  @line_number_attribute = options[:line_number_attribute]
  @file_name_attribute = options[:file_name_attribute]
  @fragment_ref_attribute = options[:fragment_ref_attribute]
  @comment_handler = options[:comment_handler]
  @comment_provider = options[:comment_provider]
  @annotation_handler = options[:annotation_handler]
  @annotation_provider = options[:annotation_provider]
  @indent_string = options[:indent_string] || "  "
  @per_type_identifier = options[:per_type_identifier]
  @backward_ref_attribute = options[:backward_ref_attribute] || proc{|c| nil}
  @generics_enabled = options[:enable_generics]
end

Instance Attribute Details

#annotation_handlerObject (readonly)

Returns the value of attribute annotation_handler.



183
184
185
# File 'lib/rtext/language.rb', line 183

def annotation_handler
  @annotation_handler
end

#annotation_providerObject (readonly)

Returns the value of attribute annotation_provider.



184
185
186
# File 'lib/rtext/language.rb', line 184

def annotation_provider
  @annotation_provider
end

#backward_ref_attributeObject (readonly)

Returns the value of attribute backward_ref_attribute.



187
188
189
# File 'lib/rtext/language.rb', line 187

def backward_ref_attribute
  @backward_ref_attribute
end

#comment_handlerObject (readonly)

Returns the value of attribute comment_handler.



181
182
183
# File 'lib/rtext/language.rb', line 181

def comment_handler
  @comment_handler
end

#comment_providerObject (readonly)

Returns the value of attribute comment_provider.



182
183
184
# File 'lib/rtext/language.rb', line 182

def comment_provider
  @comment_provider
end

#file_name_attributeObject (readonly)

Returns the value of attribute file_name_attribute.



179
180
181
# File 'lib/rtext/language.rb', line 179

def file_name_attribute
  @file_name_attribute
end

#fragment_ref_attributeObject (readonly)

Returns the value of attribute fragment_ref_attribute.



180
181
182
# File 'lib/rtext/language.rb', line 180

def fragment_ref_attribute
  @fragment_ref_attribute
end

#generics_enabledObject (readonly)

Returns the value of attribute generics_enabled.



188
189
190
# File 'lib/rtext/language.rb', line 188

def generics_enabled
  @generics_enabled
end

#identifier_providerObject (readonly)

Returns the value of attribute identifier_provider.



176
177
178
# File 'lib/rtext/language.rb', line 176

def identifier_provider
  @identifier_provider
end

#indent_stringObject (readonly)

Returns the value of attribute indent_string.



185
186
187
# File 'lib/rtext/language.rb', line 185

def indent_string
  @indent_string
end

#line_number_attributeObject (readonly)

Returns the value of attribute line_number_attribute.



178
179
180
# File 'lib/rtext/language.rb', line 178

def line_number_attribute
  @line_number_attribute
end

#per_type_identifierObject (readonly)

Returns the value of attribute per_type_identifier.



186
187
188
# File 'lib/rtext/language.rb', line 186

def per_type_identifier
  @per_type_identifier
end

#reference_qualifierObject (readonly)

Returns the value of attribute reference_qualifier.



177
178
179
# File 'lib/rtext/language.rb', line 177

def reference_qualifier
  @reference_qualifier
end

#reference_regexpObject (readonly)

Returns the value of attribute reference_regexp.



175
176
177
# File 'lib/rtext/language.rb', line 175

def reference_regexp
  @reference_regexp
end

#root_classesObject (readonly)

Returns the value of attribute root_classes.



174
175
176
# File 'lib/rtext/language.rb', line 174

def root_classes
  @root_classes
end

#root_epackageObject (readonly)

Returns the value of attribute root_epackage.



173
174
175
# File 'lib/rtext/language.rb', line 173

def root_epackage
  @root_epackage
end

Instance Method Details

#argument_format(feature) ⇒ Object



231
232
233
# File 'lib/rtext/language.rb', line 231

def argument_format(feature)
  @argument_format_provider && @argument_format_provider.call(feature)
end

#class_by_command(command, context_class) ⇒ Object



190
191
192
193
# File 'lib/rtext/language.rb', line 190

def class_by_command(command, context_class)
  map = @class_by_command[context_class]
  map && map[command]
end

#command_by_class(clazz) ⇒ Object



199
200
201
# File 'lib/rtext/language.rb', line 199

def command_by_class(clazz)
  @command_by_class[clazz]
end

#concrete_types(clazz) ⇒ Object



235
236
237
# File 'lib/rtext/language.rb', line 235

def concrete_types(clazz)
  ([clazz] + clazz.eAllSubTypes).select{|c| !c.abstract}
end

#containments(clazz) ⇒ Object



203
204
205
# File 'lib/rtext/language.rb', line 203

def containments(clazz)
  features(clazz).select{|f| f.is_a?(RGen::ECore::EReference) && f.containment}
end

#containments_by_target_type(clazz, type) ⇒ Object



239
240
241
242
243
244
245
246
# File 'lib/rtext/language.rb', line 239

def containments_by_target_type(clazz, type)
  map = {}
  containments(clazz).each do |r|
    concrete_types(r.eType).each {|t| (map[t] ||= []) << r}
  end
  # the following line should be unnecessary with exception of "uniq"
  ([type]+type.eAllSuperTypes).inject([]){|m,t| m + (map[t] || []) }.uniq
end

#feature_by_name(clazz, name) ⇒ Object



248
249
250
# File 'lib/rtext/language.rb', line 248

def feature_by_name(clazz, name)
  clazz.eAllStructuralFeatures.find{|f| f.name == name}
end

#file_name(element) ⇒ Object



252
253
254
# File 'lib/rtext/language.rb', line 252

def file_name(element)
  @file_name_attribute && element.respond_to?(@file_name_attribute) && element.send(@file_name_attribute)
end

#fragment_ref(element) ⇒ Object



260
261
262
263
264
265
266
# File 'lib/rtext/language.rb', line 260

def fragment_ref(element)
  begin
    @fragment_ref_attribute && element.send(@fragment_ref_attribute) 
  rescue NoMethodError
    false
  end
end

#has_command(command) ⇒ Object



195
196
197
# File 'lib/rtext/language.rb', line 195

def has_command(command)
  @has_command[command]
end

#labeled_containment?(clazz, feature) ⇒ Boolean

Returns:

  • (Boolean)


226
227
228
229
# File 'lib/rtext/language.rb', line 226

def labeled_containment?(clazz, feature)
  return false unless @labeled_containments
  @labeled_containments.call(clazz).include?(feature.name)
end

#labled_arguments(clazz) ⇒ Object



211
212
213
# File 'lib/rtext/language.rb', line 211

def labled_arguments(clazz)
  non_containments(clazz) - unlabled_arguments(clazz)
end

#line_number(element) ⇒ Object



256
257
258
# File 'lib/rtext/language.rb', line 256

def line_number(element)
  @line_number_attribute && element.respond_to?(@line_number_attribute) && element.send(@line_number_attribute)
end

#non_containments(clazz) ⇒ Object



207
208
209
# File 'lib/rtext/language.rb', line 207

def non_containments(clazz)
  features(clazz).reject{|f| f.is_a?(RGen::ECore::EReference) && f.containment}
end

#unlabled_arguments(clazz) ⇒ Object



215
216
217
218
219
# File 'lib/rtext/language.rb', line 215

def unlabled_arguments(clazz)
  return [] unless @unlabled_arguments
  uargs = @unlabled_arguments.call(clazz) || []
  uargs.collect{|a| non_containments(clazz).find{|f| f.name == a}}.compact
end

#unquoted?(feature) ⇒ Boolean

Returns:

  • (Boolean)


221
222
223
224
# File 'lib/rtext/language.rb', line 221

def unquoted?(feature)
  return false unless @unquoted_arguments
  @unquoted_arguments.call(feature.eContainingClass).include?(feature.name)
end