~ubuntu-branches/ubuntu/oneiric/ctioga2/oneiric

« back to all changes in this revision

Viewing changes to lib/ctioga2/commands/interpreter.rb

  • Committer: Bazaar Package Importer
  • Author(s): Vincent Fourmond
  • Date: 2011-01-24 21:36:06 UTC
  • Revision ID: james.westby@ubuntu.com-20110124213606-9ettx0ugl83z0bzp
Tags: upstream-0.1
ImportĀ upstreamĀ versionĀ 0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# interpreter.rb: the interpreter of commands
 
2
# copyright (c) 2009 by Vincent Fourmond
 
3
  
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
  
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details (in the COPYING file).
 
13
 
 
14
require 'ctioga2/utils'
 
15
require 'ctioga2/commands/commands'
 
16
require 'ctioga2/commands/variables'
 
17
require 'ctioga2/commands/strings'
 
18
require 'ctioga2/commands/parsers/command-line'
 
19
require 'ctioga2/commands/doc/doc'
 
20
 
 
21
module CTioga2
 
22
 
 
23
  Version::register_svn_info('$Revision: 155 $', '$Date: 2010-06-21 21:41:32 +0200 (Mon, 21 Jun 2010) $')
 
24
 
 
25
  # This module contains the real core of ctioga2: a set of classes
 
26
  # that implement the concept of commands. Each command translates
 
27
  # into an action (of any kind).
 
28
  #
 
29
  # Commands can be specified using several ways: either using command-line
 
30
  # options/arguments or through a commands file.
 
31
  module Commands
 
32
 
 
33
    # An exception raised when a command is defined twice
 
34
    class DoubleDefinition < Exception
 
35
    end
 
36
 
 
37
    # An exception raised when a command is not known to the interpreter
 
38
    class UnknownCommand < Exception
 
39
    end
 
40
 
 
41
    # An exception raised upon invalid names.
 
42
    class InvalidName < Exception
 
43
    end
 
44
 
 
45
    # An exception raised when a CommandType is not known
 
46
    class InvalidType < Exception
 
47
    end
 
48
 
 
49
    # A CommandGroup#id or Command#name should match this regular
 
50
    # expression.
 
51
    NameValidationRE = /^[a-z0-9-]+$/
 
52
 
 
53
    # The core class interpreting all the commands and executing them.
 
54
    # It holds a hash class variable containing all the Command
 
55
    # objects defined so far.
 
56
    class Interpreter
 
57
 
 
58
      # All commands defined so far.
 
59
      @@commands = {}
 
60
 
 
61
      # All command groups defined so far.
 
62
      @@groups = {}
 
63
 
 
64
      # All types defined so fat
 
65
      @@types = {}
 
66
 
 
67
 
 
68
 
 
69
      # Registers a given command. This is called automatically from
 
70
      # Command.new, so you should not have to do it yourself.
 
71
      def self.register_command(command)
 
72
        if self.command(command.name)
 
73
          raise DoubleDefinition, "Command '#{command.name}' already defined"
 
74
        else
 
75
          if command.name =~ NameValidationRE
 
76
            @@commands[command.name] = command
 
77
          else
 
78
            raise InvalidName, "Name '#{command.name}' is invalid"
 
79
          end
 
80
        end
 
81
      end
 
82
 
 
83
      # Registers a given group. This is called automatically from
 
84
      # CommandGroup.new, so you should not have to do it yourself.
 
85
      def self.register_group(group)
 
86
        if self.group(group.id)
 
87
          raise DoubleDefinition, "Group '#{group.id}' already defined"
 
88
        else
 
89
          if group.id =~ NameValidationRE
 
90
            @@groups[group.id] = group
 
91
          else
 
92
            raise InvalidName, "Name '#{group.id}' is invalid"
 
93
          end
 
94
        end
 
95
      end
 
96
 
 
97
      # Registers a given type. This is called automatically from
 
98
      # CommandType.new, so you should not have to do it yourself.
 
99
      def self.register_type(type)
 
100
        if self.type(type.name)
 
101
          raise DoubleDefinition, "Type '#{type.name}' already defined"
 
102
        else
 
103
          if type.name =~ NameValidationRE
 
104
            @@types[type.name] = type
 
105
          else
 
106
            raise InvalidName, "Name '#{type.name}' is invalid"
 
107
          end
 
108
        end
 
109
      end
 
110
 
 
111
 
 
112
      # Returns the named CommandType
 
113
      def self.type(name)
 
114
        return @@types[name]
 
115
      end
 
116
 
 
117
      # Returns all registered CommandType objects
 
118
      def self.types
 
119
        return @@types
 
120
      end
 
121
 
 
122
      # Deletes a command whose name is given
 
123
      def self.delete_command(cmd)
 
124
        @@commands.delete(cmd)
 
125
      end
 
126
 
 
127
      # Returns the command given by its name _cmd_, or nil if none was found.
 
128
      def self.command(cmd)
 
129
        return @@commands[cmd]
 
130
      end
 
131
 
 
132
      # Returns the groups given by its _id_, or nil if none was found.
 
133
      def self.group(id)
 
134
        return @@groups[id]
 
135
      end
 
136
 
 
137
      # Returns the commands hash
 
138
      def self.commands
 
139
        return @@commands
 
140
      end
 
141
 
 
142
      # Returns the groups hash
 
143
      def self.groups
 
144
        return @@groups
 
145
      end
 
146
 
 
147
      # A Variables object holding the ... variables ! (I'm sure you
 
148
      # guessed it !)
 
149
      attr_accessor :variables
 
150
 
 
151
      # The PlotMaker object that will receive the commands of the
 
152
      # Interpreter. 
 
153
      attr_accessor :plotmaker_target
 
154
 
 
155
      # The Parsers::CommandLineParser object used to... parse the command-line.
 
156
      # (surprising, isn't it ??)
 
157
      attr_reader :command_line_parser
 
158
 
 
159
      # The Documentation::Doc object that can interact with documentation
 
160
      attr_reader :doc
 
161
 
 
162
      # The Parsers::FileParser object used to... parse files ?
 
163
      attr_reader :file_parser
 
164
 
 
165
      # Creates an Interpreter with _target_ as the PlotMaker target
 
166
      # object.
 
167
      #
 
168
      # As far as command-line and help is concerned, it takes a
 
169
      # snapshot of the current commands known to the system, so
 
170
      # please instantiate it last.
 
171
      #
 
172
      # \todo probably this behavior is not really desired.
 
173
      # Easy to fix.
 
174
      def initialize(target)
 
175
        @plotmaker_target = target
 
176
        @command_line_parser = 
 
177
          Parsers::CommandLineParser.new(@@commands.values, 
 
178
                                         CTioga2::PlotMaker::PlotCommand)
 
179
 
 
180
        @doc = Documentation::Doc.new()
 
181
        @variables = Variables.new
 
182
 
 
183
        @file_parser = Parsers::FileParser.new
 
184
      end
 
185
 
 
186
 
 
187
      # Parses and run the given command-line, sending the commands to
 
188
      # the #plotmaker_target.
 
189
      def run_command_line(args)
 
190
        @command_line_parser.parse_command_line(args, self) do |arg|
 
191
          puts "Non-optional argument: #{arg.first}"
 
192
        end
 
193
      end
 
194
 
 
195
      # Parses and runs the given file. Sets PlotMaker#figure_name to
 
196
      # the base name of the given file if no figure name was
 
197
      # specified.
 
198
      def run_command_file(file)
 
199
        @file_parser.run_command_file(file, self)
 
200
        if ! @plotmaker_target.figure_name
 
201
          @plotmaker_target.figure_name = file.gsub(/\.[^.]+$/,'')
 
202
        end
 
203
      end
 
204
 
 
205
      # Parses and runs the given string.
 
206
      def run_commands(string)
 
207
        @file_parser.run_commands(string, self)
 
208
      end
 
209
 
 
210
      # Returns a Command object corresponding to the given _symbol_, or
 
211
      # raises an UnknownCommand exception.
 
212
      def get_command(symbol)
 
213
        if @@commands.key? symbol
 
214
          return @@commands[symbol]
 
215
        else
 
216
          raise UnknownCommand, "Unknown command: #{symbol}"
 
217
        end
 
218
      end
 
219
 
 
220
      # Returns the list of all know command names
 
221
      def command_names
 
222
        return @@commands.keys
 
223
      end
 
224
 
 
225
      # Runs _command_ with the given _arguments_ and _options_,
 
226
      # converting them as necessary. All the commands ran from this
 
227
      # interpreter should be ran from here.
 
228
      #
 
229
      # _command_ can be either a String or a Command
 
230
      #
 
231
      # Later, it could be a good idea to add a spying mechanism here.
 
232
      def run_command(command, arguments, options = nil)
 
233
        converted_args = command.convert_arguments(arguments)
 
234
        if options
 
235
          converted_options = command.convert_options(options)
 
236
        else
 
237
          converted_options = nil
 
238
        end
 
239
        command.run_command(@plotmaker_target, converted_args,
 
240
                            converted_options)
 
241
      end
 
242
    end
 
243
  end
 
244
  
 
245
  # An alias for Commands::Command
 
246
  Cmd = Commands::Command
 
247
 
 
248
  # An alias for Commands::CommandArgument
 
249
  CmdArg = Commands::CommandArgument
 
250
 
 
251
  # An alias for Commands::CommandGroup
 
252
  CmdGroup = Commands::CommandGroup
 
253
 
 
254
  # An alias for Commands::CommandType
 
255
  CmdType = Commands::CommandType
 
256
end
 
257