gauge-ruby 0.4.2 → 0.4.3

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 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