gauge-ruby 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7eae6ad6fe9c27f238406b2e4309ee08ba70f360
4
- data.tar.gz: 9372308c2f74fe4b24437992ec71b6590f68c53d
3
+ metadata.gz: 86bb6e44e272971e83b2bef3c38dd92106cae506
4
+ data.tar.gz: cfdf3a81e93b61c3acc54da0a123630781043860
5
5
  SHA512:
6
- metadata.gz: 8b41d7a8fa4bf549200a1d2323292d364cf7b455c67eae939c53d8676335ff98cd798996854dcb9994c073bc7a25a5086840190cb99472fc2019289f03e45dae
7
- data.tar.gz: 359dc83b45668e572aa2d58ff1f547372a9d2cf71397f7ad178ad69fbc73e76e50f3e96d880447d28c1e8679d166f3e43b3c5e0fedf9011f694234ef3d8e98d5
6
+ metadata.gz: 36640d7d7936fc4600b7dc1040b922f893bd72ff4e1a514251fefba70a16459009c508031c57e328c59b87da07e4845622409f5da1c4539a66426fa074660042
7
+ data.tar.gz: 220d4b472ee354d203bcbe35ab54f40f33be040d9eb8b664fc6e5001b0c5888f5000cd508fb4de196f6ed7a831641a2ee54f156247846a97af9846495016a341
@@ -16,7 +16,6 @@ module Gauge
16
16
  class GetAllStepsResponse < ::ProtocolBuffers::Message; end
17
17
  class SpecsRequest < ::ProtocolBuffers::Message; end
18
18
  class SpecsResponse < ::ProtocolBuffers::Message; end
19
- class Error < ::ProtocolBuffers::Message; end
20
19
  class GetAllConceptsRequest < ::ProtocolBuffers::Message; end
21
20
  class GetAllConceptsResponse < ::ProtocolBuffers::Message; end
22
21
  class ConceptInfo < ::ProtocolBuffers::Message; end
@@ -27,7 +26,6 @@ module Gauge
27
26
  class ErrorResponse < ::ProtocolBuffers::Message; end
28
27
  class PerformRefactoringRequest < ::ProtocolBuffers::Message; end
29
28
  class PerformRefactoringResponse < ::ProtocolBuffers::Message; end
30
- class ExtractConceptInfoRequest < ::ProtocolBuffers::Message; end
31
29
  class ExtractConceptRequest < ::ProtocolBuffers::Message; end
32
30
  class TextInfo < ::ProtocolBuffers::Message; end
33
31
  class Step < ::ProtocolBuffers::Message; end
@@ -93,14 +91,6 @@ module Gauge
93
91
  repeated ::Gauge::Messages::SpecsResponse::SpecDetail, :details, 1
94
92
  end
95
93
 
96
- class Error < ::ProtocolBuffers::Message
97
- set_fully_qualified_name "gauge.messages.Error"
98
-
99
- optional :string, :filename, 1
100
- optional :int32, :lineNumber, 2
101
- optional :string, :message, 3
102
- end
103
-
104
94
  class GetAllConceptsRequest < ::ProtocolBuffers::Message
105
95
  set_fully_qualified_name "gauge.messages.GetAllConceptsRequest"
106
96
 
@@ -166,12 +156,6 @@ module Gauge
166
156
  repeated :string, :filesChanged, 3
167
157
  end
168
158
 
169
- class ExtractConceptInfoRequest < ::ProtocolBuffers::Message
170
- set_fully_qualified_name "gauge.messages.ExtractConceptInfoRequest"
171
-
172
- optional :string, :text, 1
173
- end
174
-
175
159
  class ExtractConceptRequest < ::ProtocolBuffers::Message
176
160
  set_fully_qualified_name "gauge.messages.ExtractConceptRequest"
177
161
 
@@ -1,4 +1,4 @@
1
- # Copyright 2015 ThoughtWorks, Inc.
1
+ # Copyright 2018 ThoughtWorks, Inc.
2
2
  #
3
3
  # This file is part of Gauge-Ruby.
4
4
  #
@@ -16,6 +16,7 @@
16
16
  # along with Gauge-Ruby. If not, see <http://www.gnu.org/licenses/>.
17
17
 
18
18
  require 'parser/current'
19
+ require 'unparser'
19
20
  require 'method_source'
20
21
  require 'fileutils'
21
22
  require 'tempfile'
@@ -24,16 +25,15 @@ require 'util'
24
25
  module Gauge
25
26
  # @api private
26
27
  class CodeParser
27
- def self.step_args_from_code(code)
28
- ast=code_to_ast(code)
28
+ def self.step_args_from_code(ast)
29
29
  arg_node = ast.children[1]
30
30
  arg_node.children
31
31
  end
32
32
 
33
- def self.refactor_args(code, param_positions, new_param_values, new_step_text)
33
+ def self.process_node(node, param_positions, new_param_values, new_step_text)
34
34
  new_params = []
35
- args = step_args_from_code code
36
- param_positions.sort_by!(&:newPosition).each.with_index { |e,i|
35
+ args = step_args_from_code node
36
+ param_positions.sort_by!(&:newPosition).each.with_index {|e, i|
37
37
  if e.oldPosition == -1
38
38
  param = Util.remove_special_chars new_param_values[e.newPosition].downcase.split.join('_')
39
39
  if param == ''
@@ -44,41 +44,56 @@ module Gauge
44
44
  new_params[e.newPosition] = args[e.oldPosition].children[0]
45
45
  end
46
46
  }
47
- buffer = Parser::Source::Buffer.new '(rewriter)'
48
- buffer.source=code
49
-
50
- ast = code_to_ast(code)
51
- new_params_string = "|#{new_params.join(', ')}|".gsub("||", "") # no params = empty string
52
-
53
- rewriter = Parser::Source::Rewriter.new(buffer)
54
- .replace(ast.children[0].location.expression, "step '#{new_step_text}'")
55
-
56
- # hack, could not find an easy way to manipulate the ast to include arguments, when none existed originally.
57
- # it's just easy to add arguments via string substitution.
58
- return include_args(rewriter.process, new_params_string) if ast.children[1].location.expression.nil?
59
-
60
- #insert new arguments
61
- rewriter.replace(ast.children[1].location.expression, new_params_string).process
47
+ args = new_params.map {|v| Parser::AST::Node.new(:arg, [v])}
48
+ step = [node.children[0].children[0], node.children[0].children[1], Parser::AST::Node.new(:str, [new_step_text])]
49
+ c1 = Parser::AST::Node.new(:send, step)
50
+ c2 = Parser::AST::Node.new(:args, args)
51
+ Parser::AST::Node.new(:block, [c1, c2, node.children[2]])
62
52
  end
63
53
 
64
- def self.refactor(code, param_positions, new_param_values, new_step_text)
65
- source_code=code.source
66
- file, _ = code.source_location
67
- refactored_code=refactor_args(source_code, param_positions, new_param_values, new_step_text)
68
- tmp_file = Tempfile.new File.basename(file, ".rb")
69
- tmp_file.write(File.open(file, "r") { |f| f.read.gsub(source_code, refactored_code)})
70
- tmp_file.close
71
- FileUtils.mv tmp_file.path, file
54
+ def self.replace(ast, &visitor)
55
+ return ast if ast.class != Parser::AST::Node
56
+ if ast && step_node?(ast)
57
+ visitor.call(ast)
58
+ else
59
+ children = ast.children.map {|node|
60
+ replace(node, &visitor)
61
+ }
62
+ return ast.updated(nil, children, nil)
63
+ end
64
+ end
65
+
66
+ def self.step_node?(node)
67
+ node.type == :block && node.children[0].children.size > 2 && node.children[0].children[1] == :step
68
+ end
69
+
70
+ def self.refactor_args(step_text, ast, param_positions, new_param_values, new_step_text)
71
+ new_ast = replace ast do |node|
72
+ if node.children[0].children[2].children[0] == step_text
73
+ process_node(node, param_positions, new_param_values, new_step_text)
74
+ else
75
+ node
76
+ end
77
+ end
78
+ Unparser.unparse new_ast
79
+ end
80
+
81
+ def self.refactor(step_info, param_positions, new_step)
82
+ ast = code_to_ast File.read(step_info[:locations][0][:file])
83
+ refactor_args(step_info[:step_text], ast, param_positions, new_step.parameters, new_step.parameterizedStepValue)
72
84
  end
73
85
 
74
86
  private
75
87
 
76
88
  def self.code_to_ast(code)
77
- buffer = Parser::Source::Buffer.new '(string)'
78
- buffer.source = code
79
-
80
- parser = Parser::CurrentRuby.new
81
- parser.parse(buffer)
89
+ begin
90
+ buffer = Parser::Source::Buffer.new '(string)'
91
+ buffer.source = code
92
+ parser = Parser::CurrentRuby.new
93
+ return parser.parse(buffer)
94
+ rescue Exception => e
95
+ Gauge::Log.error e.message
96
+ end
82
97
  end
83
98
 
84
99
  def self.include_args(code_string, params)
@@ -22,22 +22,16 @@ module Gauge
22
22
  # @api private
23
23
  module Connector
24
24
  GAUGE_PORT_ENV = "GAUGE_INTERNAL_PORT"
25
- API_PORT_ENV = "GAUGE_API_PORT"
26
25
  HOST_NAME = 'localhost'
27
26
  @@executionSocket = nil
28
- @@apiSocket = nil
29
27
 
30
- def self.apiSocket
31
- @@apiSocket
32
- end
33
28
 
34
- def self.executionSocket
29
+ def self.execution_socket
35
30
  @@executionSocket
36
31
  end
37
32
 
38
- def self.make_connections
39
- @@executionSocket = TCPSocket.open(HOST_NAME, Runtime.portFromEnvVariable(GAUGE_PORT_ENV))
40
- @@apiSocket = TCPSocket.open(HOST_NAME, Runtime.portFromEnvVariable(API_PORT_ENV))
33
+ def self.make_connection
34
+ @@executionSocket = TCPSocket.open(HOST_NAME, Runtime.port_from_env_variable(GAUGE_PORT_ENV))
41
35
  end
42
36
 
43
37
  def self.message_length(socket)
@@ -45,29 +39,7 @@ module Gauge
45
39
  end
46
40
 
47
41
  def self.step_value text
48
- stepValueRequest = Gauge::Messages::GetStepValueRequest.new(:stepText => text)
49
- apiMessage = Gauge::Messages::APIMessage.new(:messageType => Gauge::Messages::APIMessage::APIMessageType::GetStepValueRequest, :stepValueRequest => stepValueRequest)
50
- response = get_api_response(apiMessage)
51
- if (response.messageType == Gauge::Messages::APIMessage::APIMessageType::ErrorResponse)
52
- puts "[Error] Failed to load step implementation. #{response.error.error}: \"#{text}\""
53
- return ''
54
- end
55
- return response.stepValueResponse.stepValue.stepValue
56
- end
57
-
58
- def self.get_api_response(apiMessage)
59
- apiMessage.messageId = get_unique_id
60
- dataLen = apiMessage.serialize_to_string.bytesize
61
- ProtocolBuffers::Varint.encode @@apiSocket, dataLen
62
- apiMessage.serialize(@@apiSocket)
63
-
64
- responseLen = message_length(@@apiSocket)
65
- data = @@apiSocket.read responseLen
66
- message = Gauge::Messages::APIMessage.parse(data)
67
- end
68
-
69
- def self.get_unique_id
70
- rand(2**63-1)
42
+ return text.gsub(/(<.*?>)/, "{}")
71
43
  end
72
44
  end
73
45
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2015 ThoughtWorks, Inc.
1
+ # Copyright 2018 ThoughtWorks, Inc.
2
2
 
3
3
  # This file is part of Gauge-Ruby.
4
4
 
@@ -14,28 +14,47 @@
14
14
 
15
15
  # You should have received a copy of the GNU General Public License
16
16
  # along with Gauge-Ruby. If not, see <http://www.gnu.org/licenses/>.
17
-
17
+ require 'ruby-debug-ide'
18
18
  require_relative 'gauge'
19
19
 
20
+ ATTACH_DEBUGGER_EVENT = "Runner Ready for Debugging"
21
+
20
22
  module Gauge
23
+ class DebugOptions
24
+ attr_accessor :host, :port, :notify_dispatcher
25
+ end
26
+
21
27
  # @api private
22
28
  module Executor
23
- def self.load_steps(steps_implementation_dir)
24
- Dir["#{steps_implementation_dir}/**/*.rb"].each { |x|
29
+ def self.load_steps(dir)
30
+ start_debugger
31
+ Dir["#{dir}/**/*.rb"].each do |x|
25
32
  begin
33
+ ENV['GAUGE_STEP_FILE'] = x
26
34
  require x
27
35
  rescue Exception => e
28
- puts "[ERROR] Cannot import #{x}. Reason: #{e.message}"
36
+ Gauge::Log.error "[ERROR] Cannot import #{x}. Reason: #{e.message}"
29
37
  end
30
- }
38
+ end
39
+ end
40
+
41
+ def self.start_debugger
42
+ if ENV['DEBUGGING']
43
+ options = DebugOptions.new
44
+ options.host = '127.0.0.1'
45
+ options.port = ENV["DEBUG_PORT"].to_i
46
+ options.notify_dispatcher = false
47
+ Gauge::Log.info ATTACH_DEBUGGER_EVENT
48
+ Debugger.prepare_debugger(options)
49
+ end
31
50
  end
32
51
 
33
52
  def self.execute_step(step, args)
34
- block = MethodCache.get_step step
53
+ si = MethodCache.get_step_info step
35
54
  if args.size == 1
36
- block.call(args[0])
55
+ si[:block].call(args[0])
37
56
  else
38
- block.call(args)
57
+ si[:block].call(args)
39
58
  end
40
59
  end
41
60
 
@@ -1,4 +1,4 @@
1
- # Copyright 2015 ThoughtWorks, Inc.
1
+ # Copyright 2018 ThoughtWorks, Inc.
2
2
 
3
3
  # This file is part of Gauge-Ruby.
4
4
 
@@ -32,7 +32,7 @@ module Kernel
32
32
  # puts "I am the $1 hook"
33
33
  # end
34
34
  def hook(hook)
35
- define_method hook do |options={}, &block|
35
+ define_method hook do |options = {}, &block|
36
36
  Gauge::MethodCache.send("add_#{hook}_hook".to_sym, options, &block)
37
37
  end
38
38
  end
@@ -104,31 +104,32 @@ module Kernel
104
104
  # @param block [block] the implementation block for given step.
105
105
  def step(*args, &block)
106
106
  opts = args.select {|x| x.is_a? Hash}
107
- step_texts = args-opts
108
- opts = {:continue_on_failure => false}.merge opts.reduce({}, :merge)
107
+ step_texts = args - opts
108
+ opts = { continue_on_failure: false }.merge opts.reduce({}, :merge)
109
109
  step_texts.each do |text|
110
- parameterized_step_text = Gauge::Connector.step_value(text)
111
- Gauge::MethodCache.add_step(parameterized_step_text, &block)
112
- Gauge::MethodCache.add_step_text(parameterized_step_text, text)
113
- Gauge::MethodCache.set_recoverable(parameterized_step_text) if opts[:continue_on_failure]
110
+ step_value = Gauge::Connector.step_value(text)
111
+ si = { location: { file: ENV['GAUGE_STEP_FILE'], span: {} },
112
+ block: block, step_text: text,
113
+ recoverable: opts[:continue_on_failure] }
114
+ Gauge::MethodCache.add_step(step_value, si)
114
115
  end
115
116
  Gauge::MethodCache.add_step_alias(*step_texts)
116
117
  end
117
118
 
118
119
  # Invoked before execution of every step.
119
- tagged_hook "before_step"
120
+ tagged_hook 'before_step'
120
121
  # Invoked after execution of every step.
121
- tagged_hook "after_step"
122
+ tagged_hook 'after_step'
122
123
  # Invoked before execution of every specification.
123
- tagged_hook "before_spec"
124
+ tagged_hook 'before_spec'
124
125
  # Invoked after execution of every specification.
125
- tagged_hook "after_spec"
126
+ tagged_hook 'after_spec'
126
127
  # Invoked before execution of every scenario.
127
- tagged_hook "before_scenario"
128
+ tagged_hook 'before_scenario'
128
129
  # Invoked after execution of every scenario.
129
- tagged_hook "after_scenario"
130
+ tagged_hook 'after_scenario'
130
131
  # Invoked before execution of the entire suite.
131
- hook "before_suite"
132
+ hook 'before_suite'
132
133
  # Invoked after execution of the entire suite.
133
- hook "after_suite"
134
+ hook 'after_suite'
134
135
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2015 ThoughtWorks, Inc.
1
+ # Copyright 2018 ThoughtWorks, Inc.
2
2
 
3
3
  # This file is part of Gauge-Ruby.
4
4
 
@@ -20,14 +20,17 @@ require 'protocol_buffers'
20
20
 
21
21
  require_relative 'messages.pb'
22
22
  require_relative 'executor'
23
+ require_relative 'static_loader'
23
24
  require_relative 'connector'
24
25
  require_relative 'message_processor'
26
+ require_relative 'util'
27
+ require_relative 'log'
25
28
 
26
29
 
27
30
  module Gauge
28
31
  # @api private
29
32
  module Runtime
30
- DEFAULT_IMPLEMENTATIONS_DIR_PATH = File.join(Dir.pwd, 'step_implementations')
33
+ DEFAULT_IMPLEMENTATIONS_DIR_PATH = Util.get_step_implementation_dir
31
34
 
32
35
  def self.dispatch_messages(socket)
33
36
  while (!socket.eof?)
@@ -35,7 +38,7 @@ module Gauge
35
38
  data = socket.read len
36
39
  message = Messages::Message.parse(data)
37
40
  handle_message(socket, message)
38
- if (message.messageType == Messages::Message::MessageType::KillProcessRequest || message.messageType == Messages::Message::MessageType::ExecutionEnding)
41
+ if message.messageType == Messages::Message::MessageType::KillProcessRequest || message.messageType == Messages::Message::MessageType::ExecutionEnding
39
42
  socket.close
40
43
  return
41
44
  end
@@ -44,14 +47,14 @@ module Gauge
44
47
 
45
48
 
46
49
  def self.handle_message(socket, message)
47
- if (!MessageProcessor.is_valid_message(message))
48
- puts "Invalid message received : #{message}"
50
+ if !MessageProcessor.is_valid_message(message)
51
+ Gauge::Log.error "Invalid message received : #{message}"
49
52
  execution_status_response = Messages::ExecutionStatusResponse.new(:executionResult => Messages::ProtoExecutionResult.new(:failed => true, :executionTime => 0))
50
53
  message = Messages::Message.new(:messageType => Messages::Message::MessageType::ExecutionStatusResponse, :messageId => message.messageId, :executionStatusResponse => execution_status_response)
51
54
  write_message(socket, message)
52
55
  else
53
56
  response = MessageProcessor.process_message message
54
- write_message(socket, response)
57
+ write_message(socket, response) if response
55
58
  end
56
59
  end
57
60
 
@@ -62,18 +65,19 @@ module Gauge
62
65
  socket.write serialized_message
63
66
  end
64
67
 
65
- def self.portFromEnvVariable(envVariable)
66
- port = ENV[envVariable]
67
- if (port.nil?)
68
- raise RuntimeError, "Could not find Env variable :#{envVariable}"
68
+ def self.port_from_env_variable(env_variable)
69
+ port = ENV[env_variable]
70
+ if port.nil?
71
+ raise RuntimeError, "Could not find Env variable :#{env_variable}"
69
72
  end
70
73
  return port
71
74
  end
72
75
 
73
76
  STDOUT.sync = true
74
- Connector.make_connections()
75
- Executor.load_steps(DEFAULT_IMPLEMENTATIONS_DIR_PATH)
76
- dispatch_messages(Connector.executionSocket)
77
+ GaugeLog.init
78
+ Connector.make_connection
79
+ StaticLoader.load_files(DEFAULT_IMPLEMENTATIONS_DIR_PATH)
80
+ dispatch_messages(Connector.execution_socket)
77
81
  exit(0)
78
82
  end
79
83
  end
@@ -0,0 +1,33 @@
1
+ # Copyright 2018 ThoughtWorks, Inc.
2
+
3
+ # This file is part of Gauge-Ruby.
4
+
5
+ # Gauge-Ruby is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # Gauge-Ruby is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Gauge-Ruby. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'logger'
19
+
20
+ module Gauge
21
+ Log = Logger.new(STDOUT)
22
+ module GaugeLog
23
+ def self.init()
24
+ Log.formatter = proc do |severity, datetime, progname, msg|
25
+ if ENV['IS_DAEMON']
26
+ "#{datetime.strftime('%H:%M:%S.%L')} #{msg}\n"
27
+ else
28
+ "#{msg}\n"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end