rtext 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +108 -98
- data/RText_Protocol +1 -1
- data/Rakefile +39 -46
- data/lib/rtext/default_completer.rb +212 -208
- data/lib/rtext/frontend/connector.rb +120 -53
- data/lib/rtext/instantiator.rb +11 -3
- data/lib/rtext/service.rb +264 -260
- data/test/completer_test.rb +606 -607
- data/test/context_builder_test.rb +952 -949
- data/test/frontend/context_test.rb +301 -302
- data/test/instantiator_test.rb +1773 -1733
- data/test/integration/test.rb +974 -968
- data/test/link_detector_test.rb +287 -288
- data/test/message_helper_test.rb +116 -117
- data/test/serializer_test.rb +1023 -1024
- data/test/tokenizer_test.rb +173 -174
- metadata +17 -19
- data/test/integration/backend.out +0 -16
- data/test/integration/frontend.log +0 -40058
| @@ -21,15 +21,21 @@ def initialize(config, options={}) | |
| 21 21 | 
             
              @outfile_provider = options[:outfile_provider]
         | 
| 22 22 | 
             
              @keep_outfile = options[:keep_outfile]
         | 
| 23 23 | 
             
              @connection_timeout = options[:connection_timeout] || 10
         | 
| 24 | 
            +
              @process_id = nil
         | 
| 24 25 | 
             
            end
         | 
| 25 26 |  | 
| 26 27 | 
             
            def execute_command(obj, options={})
         | 
| 27 | 
            -
              timeout = options[:timeout] ||  | 
| 28 | 
            +
              timeout = options[:timeout] || 10
         | 
| 28 29 | 
             
              @busy = false if @busy_start_time && (Time.now > @busy_start_time + timeout)
         | 
| 29 30 | 
             
              if @busy
         | 
| 30 31 | 
             
                do_work
         | 
| 31 | 
            -
                :backend_busy 
         | 
| 32 | 
            -
               | 
| 32 | 
            +
                return :backend_busy 
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
              unless connected?
         | 
| 35 | 
            +
                connect unless connecting?
         | 
| 36 | 
            +
                do_work
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
              if connected?
         | 
| 33 39 | 
             
                obj["invocation_id"] = @invocation_id
         | 
| 34 40 | 
             
                obj["type"] = "request"
         | 
| 35 41 | 
             
                @socket.send(serialize_message(obj), 0)
         | 
| @@ -66,9 +72,7 @@ def execute_command(obj, options={}) | |
| 66 72 | 
             
                  result
         | 
| 67 73 | 
             
                end
         | 
| 68 74 | 
             
              else
         | 
| 69 | 
            -
                 | 
| 70 | 
            -
                do_work
         | 
| 71 | 
            -
                :connecting 
         | 
| 75 | 
            +
                :connecting
         | 
| 72 76 | 
             
              end
         | 
| 73 77 | 
             
            end
         | 
| 74 78 |  | 
| @@ -87,23 +91,68 @@ def stop | |
| 87 91 | 
             
                  sleep(0.1)
         | 
| 88 92 | 
             
                end
         | 
| 89 93 | 
             
              end
         | 
| 94 | 
            +
              ensure_process_cleanup(@process_id, @keep_outfile ? nil : @out_file, 10)
         | 
| 95 | 
            +
              @process_id = nil
         | 
| 90 96 | 
             
            end
         | 
| 91 97 |  | 
| 92 98 | 
             
            private
         | 
| 93 99 |  | 
| 100 | 
            +
            def wait_for_process_to_exit(process_id, timeout)
         | 
| 101 | 
            +
              with_timeout timeout do
         | 
| 102 | 
            +
                begin
         | 
| 103 | 
            +
                  waitpid(process_id, Process::WNOHANG)
         | 
| 104 | 
            +
                  process_id = nil
         | 
| 105 | 
            +
                  true
         | 
| 106 | 
            +
                rescue Errno::ECHILD => _
         | 
| 107 | 
            +
                  false
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
              end
         | 
| 110 | 
            +
            end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            def ensure_process_cleanup(process_id, out_file, timeout)
         | 
| 113 | 
            +
              Thread.new do
         | 
| 114 | 
            +
                begin
         | 
| 115 | 
            +
                  unless process_id.nil?
         | 
| 116 | 
            +
                    process_id = nil if wait_for_process_to_exit(process_id, timeout)
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                ensure
         | 
| 119 | 
            +
                  unless process_id.nil?
         | 
| 120 | 
            +
                    begin
         | 
| 121 | 
            +
                      Process.kill('QUIT', process_id)
         | 
| 122 | 
            +
                    rescue Errno::ESRCH => _
         | 
| 123 | 
            +
                    end
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
                  File.unlink(out_file) if !out_file.nil? && File.exist?(out_file)
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
              end
         | 
| 128 | 
            +
            end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            def with_timeout(timeout, sleep_time = 0.1, &block)
         | 
| 131 | 
            +
              started = Time.now
         | 
| 132 | 
            +
              while true do
         | 
| 133 | 
            +
                return true if block.call
         | 
| 134 | 
            +
                if Time.now > started + timeout
         | 
| 135 | 
            +
                  return false
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
                sleep(sleep_time)
         | 
| 138 | 
            +
              end
         | 
| 139 | 
            +
            end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
             | 
| 94 142 | 
             
            def connected?
         | 
| 95 | 
            -
              @state == : | 
| 143 | 
            +
              !@process_id.nil? && @state == :read_from_socket && backend_running?
         | 
| 96 144 | 
             
            end
         | 
| 97 145 |  | 
| 98 146 | 
             
            def connecting?
         | 
| 99 | 
            -
              @state == : | 
| 147 | 
            +
              !@process_id.nil? && (@state == :wait_for_file || @state == :wait_for_port)
         | 
| 100 148 | 
             
            end
         | 
| 101 149 |  | 
| 102 150 | 
             
            def backend_running?
         | 
| 103 151 | 
             
              if @process_id
         | 
| 104 152 | 
             
                begin
         | 
| 105 | 
            -
                   | 
| 106 | 
            -
             | 
| 153 | 
            +
                  waitpid(@process_id, Process::WNOHANG)
         | 
| 154 | 
            +
                  return true
         | 
| 155 | 
            +
                rescue Errno::ECHILD => _
         | 
| 107 156 | 
             
                end
         | 
| 108 157 | 
             
              end
         | 
| 109 158 | 
             
              false
         | 
| @@ -121,7 +170,7 @@ def tempfile_name | |
| 121 170 | 
             
            end
         | 
| 122 171 |  | 
| 123 172 | 
             
            def connect
         | 
| 124 | 
            -
               | 
| 173 | 
            +
              return if connected?
         | 
| 125 174 | 
             
              @connect_start_time = Time.now
         | 
| 126 175 |  | 
| 127 176 | 
             
              @logger.info @config.command if @logger
         | 
| @@ -131,56 +180,75 @@ def connect | |
| 131 180 | 
             
              else
         | 
| 132 181 | 
             
                @out_file = tempfile_name 
         | 
| 133 182 | 
             
              end
         | 
| 134 | 
            -
              File.unlink(@out_file) if File.exist?(@out_file)
         | 
| 135 183 |  | 
| 136 | 
            -
               | 
| 137 | 
            -
                @ | 
| 184 | 
            +
              if @process_id.nil?
         | 
| 185 | 
            +
                File.unlink(@out_file) if File.exist?(@out_file)
         | 
| 186 | 
            +
                Dir.chdir(File.dirname(@config.file)) do
         | 
| 187 | 
            +
                  @process_id = spawn(@config.command.strip + " > #{@out_file} 2>&1")
         | 
| 188 | 
            +
                  @state = :wait_for_file
         | 
| 189 | 
            +
                end
         | 
| 138 190 | 
             
              end
         | 
| 139 | 
            -
              @work_state = :wait_for_file
         | 
| 140 191 | 
             
            end
         | 
| 141 192 |  | 
| 142 193 | 
             
            def do_work
         | 
| 143 | 
            -
               | 
| 144 | 
            -
             | 
| 145 | 
            -
                 | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
                 | 
| 149 | 
            -
             | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 153 | 
            -
             | 
| 194 | 
            +
              if @process_id.nil?
         | 
| 195 | 
            +
                @state = :off
         | 
| 196 | 
            +
                return false
         | 
| 197 | 
            +
              end
         | 
| 198 | 
            +
              if @state == :wait_for_port && !File.exist?(@out_file)
         | 
| 199 | 
            +
                @state = :wait_for_file
         | 
| 200 | 
            +
              end
         | 
| 201 | 
            +
              if @state == :wait_for_file && File.exist?(@out_file)
         | 
| 202 | 
            +
                @state = :wait_for_port
         | 
| 203 | 
            +
              end
         | 
| 204 | 
            +
              if @state == :wait_for_file
         | 
| 205 | 
            +
                while true
         | 
| 206 | 
            +
                  if Time.now > @connect_start_time + @connection_timeout
         | 
| 207 | 
            +
                    cleanup
         | 
| 208 | 
            +
                    @connection_listener.call(:timeout) if @connection_listener
         | 
| 209 | 
            +
                    @state = :off
         | 
| 210 | 
            +
                    @logger.warn "process didn't startup (connection timeout)" if @logger
         | 
| 211 | 
            +
                    return false
         | 
| 212 | 
            +
                  end
         | 
| 213 | 
            +
                  sleep(0.1)
         | 
| 214 | 
            +
                  if File.exist?(@out_file)
         | 
| 215 | 
            +
                    @state = :wait_for_port
         | 
| 216 | 
            +
                    break
         | 
| 217 | 
            +
                  end
         | 
| 154 218 | 
             
                end
         | 
| 155 | 
            -
             | 
| 156 | 
            -
               | 
| 157 | 
            -
                 | 
| 158 | 
            -
             | 
| 159 | 
            -
                   | 
| 160 | 
            -
                   | 
| 161 | 
            -
             | 
| 162 | 
            -
                    @ | 
| 163 | 
            -
                     | 
| 164 | 
            -
             | 
| 219 | 
            +
              end
         | 
| 220 | 
            +
              if @state == :wait_for_port
         | 
| 221 | 
            +
                while true
         | 
| 222 | 
            +
                  break unless File.exist?(@out_file)
         | 
| 223 | 
            +
                  output = File.read(@out_file)
         | 
| 224 | 
            +
                  if output =~ /^RText service, listening on port (\d+)/
         | 
| 225 | 
            +
                    port = $1.to_i
         | 
| 226 | 
            +
                    @logger.info "connecting to #{port}" if @logger
         | 
| 227 | 
            +
                    begin
         | 
| 228 | 
            +
                      @socket = TCPSocket.new("127.0.0.1", port)
         | 
| 229 | 
            +
                      @socket.setsockopt(:SOCKET, :RCVBUF, 1000000)
         | 
| 230 | 
            +
                    rescue Errno::ECONNREFUSED
         | 
| 231 | 
            +
                      cleanup
         | 
| 232 | 
            +
                      @connection_listener.call(:timeout) if @connection_listener
         | 
| 233 | 
            +
                      @state = :off
         | 
| 234 | 
            +
                      @logger.warn "could not connect socket (connection timeout)" if @logger
         | 
| 235 | 
            +
                      return false
         | 
| 236 | 
            +
                    end
         | 
| 237 | 
            +
                    @state = :read_from_socket
         | 
| 238 | 
            +
                    @connection_listener.call(:connected) if @connection_listener
         | 
| 239 | 
            +
                    break
         | 
| 240 | 
            +
                  end
         | 
| 241 | 
            +
                  if Time.now > @connect_start_time + @connection_timeout
         | 
| 165 242 | 
             
                    cleanup
         | 
| 166 243 | 
             
                    @connection_listener.call(:timeout) if @connection_listener
         | 
| 167 | 
            -
                    @work_state = :done
         | 
| 168 244 | 
             
                    @state = :off
         | 
| 169 245 | 
             
                    @logger.warn "could not connect socket (connection timeout)" if @logger
         | 
| 246 | 
            +
                    return false
         | 
| 170 247 | 
             
                  end
         | 
| 171 | 
            -
                   | 
| 172 | 
            -
                  @work_state = :read_from_socket
         | 
| 173 | 
            -
                  @connection_listener.call(:connected) if @connection_listener
         | 
| 174 | 
            -
                end
         | 
| 175 | 
            -
                if Time.now > @connect_start_time + @connection_timeout
         | 
| 176 | 
            -
                  cleanup
         | 
| 177 | 
            -
                  @connection_listener.call(:timeout) if @connection_listener
         | 
| 178 | 
            -
                  @work_state = :done
         | 
| 179 | 
            -
                  @state = :off
         | 
| 180 | 
            -
                  @logger.warn "could not connect socket (connection timeout)" if @logger
         | 
| 248 | 
            +
                  sleep(0.1)
         | 
| 181 249 | 
             
                end
         | 
| 182 | 
            -
             | 
| 183 | 
            -
               | 
| 250 | 
            +
              end
         | 
| 251 | 
            +
              if @state == :read_from_socket
         | 
| 184 252 | 
             
                repeat = true
         | 
| 185 253 | 
             
                socket_closed = false
         | 
| 186 254 | 
             
                response_data = ""
         | 
| @@ -208,13 +276,12 @@ def do_work | |
| 208 276 | 
             
                    end
         | 
| 209 277 | 
             
                  elsif !backend_running? || socket_closed
         | 
| 210 278 | 
             
                    cleanup
         | 
| 211 | 
            -
                    @ | 
| 279 | 
            +
                    @state = :off
         | 
| 212 280 | 
             
                    return false
         | 
| 213 281 | 
             
                  end
         | 
| 214 282 | 
             
                end
         | 
| 215 | 
            -
                true
         | 
| 216 283 | 
             
              end
         | 
| 217 | 
            -
             | 
| 284 | 
            +
              true
         | 
| 218 285 | 
             
            end
         | 
| 219 286 |  | 
| 220 287 | 
             
            def cleanup
         | 
| @@ -224,7 +291,7 @@ def cleanup | |
| 224 291 | 
             
                break unless backend_running?
         | 
| 225 292 | 
             
                sleep(0.1)
         | 
| 226 293 | 
             
              end
         | 
| 227 | 
            -
               | 
| 294 | 
            +
              ensure_process_cleanup(@process_id, @keep_outfile ? @out_file : nil, 10)
         | 
| 228 295 | 
             
            end
         | 
| 229 296 |  | 
| 230 297 | 
             
            end
         | 
    
        data/lib/rtext/instantiator.rb
    CHANGED
    
    | @@ -247,7 +247,15 @@ class Instantiator | |
| 247 247 | 
             
                    element.setOrAddGeneric(feature.name, proxy)
         | 
| 248 248 | 
             
                  else
         | 
| 249 249 | 
             
                    begin
         | 
| 250 | 
            -
                       | 
| 250 | 
            +
                      v_value = v.value
         | 
| 251 | 
            +
                      feature_instance_class = feature.eType.instanceClass
         | 
| 252 | 
            +
                      if feature_instance_class == String && (v_value.is_a?(Float) || v_value.is_a?(Fixnum))
         | 
| 253 | 
            +
                        element.setOrAddGeneric(feature.name, v_value.to_s)
         | 
| 254 | 
            +
                      elsif feature_instance_class == Float && v_value.is_a?(Fixnum)
         | 
| 255 | 
            +
                        element.setOrAddGeneric(feature.name, v_value.to_f)
         | 
| 256 | 
            +
                      else
         | 
| 257 | 
            +
                        element.setOrAddGeneric(feature.name, v_value)
         | 
| 258 | 
            +
                      end
         | 
| 251 259 | 
             
                    rescue StandardError
         | 
| 252 260 | 
             
                      # backward compatibility for RGen versions not supporting BigDecimal
         | 
| 253 261 | 
             
                      if v.value.is_a?(BigDecimal)
         | 
| @@ -302,9 +310,9 @@ class Instantiator | |
| 302 310 | 
             
                elsif feature.eType.is_a?(RGen::ECore::EEnum)
         | 
| 303 311 | 
             
                  [:identifier, :string]
         | 
| 304 312 | 
             
                else
         | 
| 305 | 
            -
                  expected = { String => [:string, :identifier],
         | 
| 313 | 
            +
                  expected = { String => [:string, :identifier, :integer, :float],
         | 
| 306 314 | 
             
                    Integer => [:integer],
         | 
| 307 | 
            -
                    Float => [:float],
         | 
| 315 | 
            +
                    Float => [:float, :integer],
         | 
| 308 316 | 
             
                    RGen::MetamodelBuilder::DataTypes::Boolean => [:boolean],
         | 
| 309 317 | 
             
                    Object => [:string, :identifier, :integer, :float, :boolean]
         | 
| 310 318 | 
             
                  }[feature.eType.instanceClass] 
         |