dredd_hooks 0.0.1 → 0.1.0

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.
@@ -0,0 +1,30 @@
1
+ module DreddHooks
2
+
3
+ HOOKS_ON_SINGLE_TRANSACTIONS = [:before, :before_validation, :after]
4
+
5
+ HOOKS_ON_MULTIPLE_TRANSACTIONS = [:before_each, :before_each_validation,
6
+ :after_each, :before_all, :after_all]
7
+
8
+ Server::EVENTS = {
9
+ beforeEach: [
10
+ :before_each,
11
+ :before,
12
+ ],
13
+ beforeEachValidation: [
14
+ :before_each_validation,
15
+ :before_validation,
16
+ ],
17
+ afterEach: [
18
+ :after,
19
+ :after_each,
20
+ ],
21
+ afterAll: [
22
+ :after_all,
23
+ ],
24
+ beforeAll: [
25
+ :before_all,
26
+ ],
27
+ }
28
+
29
+ end
30
+
@@ -0,0 +1,15 @@
1
+ module DreddHooks
2
+
3
+ class UnknownHookError < RuntimeError
4
+
5
+ def initialize(hook_name)
6
+ @hook_name = hook_name
7
+ end
8
+
9
+ def to_s
10
+ "Unknown hook: #{@hook_name}"
11
+ end
12
+ end
13
+
14
+ end
15
+
@@ -1,18 +1,20 @@
1
1
  module DreddHooks
2
2
  module FileLoader
3
- def self.unique_paths globs
4
- paths = []
5
- globs.each do |glob|
6
- paths += Dir.glob glob
7
- end
8
- paths.uniq
9
- end
10
3
 
11
- def self.load globs
12
- self.unique_paths(globs).each do |path|
4
+ def self.load(patterns)
5
+ unique_paths(patterns).each do |path|
13
6
  puts path
14
7
  require path
15
8
  end
16
9
  end
10
+
11
+
12
+ def self.unique_paths(patterns)
13
+ patterns.inject([]) { |paths, pattern|
14
+ paths + Dir.glob(pattern)
15
+ }.uniq
16
+ end
17
+ private_class_method :unique_paths
17
18
  end
18
- end
19
+ end
20
+
@@ -1,53 +1,59 @@
1
- module DreddHooks
2
- module Methods
3
- @@before_hooks = {}
4
- @@before_validation_hooks = {}
5
- @@after_hooks = {}
1
+ require 'dredd_hooks/definitions'
2
+ require 'dredd_hooks/runner'
6
3
 
7
- @@before_each_hooks = []
8
- @@before_each_validation_hooks = []
9
- @@after_each_hooks = []
4
+ module DreddHooks
10
5
 
11
- @@before_all_hooks = []
12
- @@after_all_hooks = []
6
+ # The Ruby hooks API
7
+ module Methods
13
8
 
9
+ # Define hook methods in the form of:
14
10
  #
15
- # Ruby hooks API
11
+ # def before(transaction_name, &block)
12
+ # runner.register_before_hook(transaction_name, &block)
13
+ # end
16
14
  #
15
+ # Hooks names are defined by HOOKS_ON_SINGLE_TRANSACTIONS.
16
+ #
17
+ # Returns nothing.
18
+ def self.define_hooks_on_single_transactions
19
+ HOOKS_ON_SINGLE_TRANSACTIONS.each do |hook_name|
17
20
 
18
- def before transaction_name, &block
19
- @@before_hooks[transaction_name] = [] if @@before_hooks[transaction_name].nil?
20
- @@before_hooks[transaction_name].push block
21
- end
21
+ define_method hook_name do |transaction_name, &block|
22
+ runner.send("register_#{hook_name}_hook", transaction_name, &block)
23
+ end
22
24
 
23
- def before_validation transaction_name, &block
24
- @@before_validation_hooks[transaction_name] = [] if @@before_validation_hooks[transaction_name].nil?
25
- @@before_validation_hooks[transaction_name].push block
25
+ end
26
26
  end
27
+ private_class_method :define_hooks_on_single_transactions
27
28
 
28
- def after transaction_name, &block
29
- @@after_hooks[transaction_name] = [] if @@after_hooks[transaction_name].nil?
30
- @@after_hooks[transaction_name].push block
31
- end
29
+ # Define hook methods in the form of:
30
+ #
31
+ # def before_all(&block)
32
+ # runner.register_before_all_hook(&block)
33
+ # end
34
+ #
35
+ # Hooks names are defined by HOOKS_ON_MULTIPLE_TRANSACTIONS.
36
+ #
37
+ # Returns nothing.
38
+ def self.define_hooks_on_multiple_transactions
39
+ HOOKS_ON_MULTIPLE_TRANSACTIONS.each do |hook_name|
32
40
 
33
- def before_each &block
34
- @@before_each_hooks.push block
35
- end
41
+ define_method hook_name do |&block|
42
+ runner.send("register_#{hook_name}_hook", &block)
43
+ end
36
44
 
37
- def before_each_validation &block
38
- @@before_each_validation_hooks.push block
45
+ end
39
46
  end
47
+ private_class_method :define_hooks_on_multiple_transactions
40
48
 
41
- def after_each &block
42
- @@after_each_hooks.push block
43
- end
49
+ define_hooks_on_single_transactions
50
+ define_hooks_on_multiple_transactions
44
51
 
45
- def before_all &block
46
- @@before_all_hooks.push block
47
- end
52
+ private
48
53
 
49
- def after_all &block
50
- @@after_all_hooks.push block
51
- end
54
+ def runner
55
+ Runner.instance
56
+ end
52
57
  end
53
- end
58
+ end
59
+
@@ -1,84 +1,141 @@
1
+ require 'singleton'
2
+
3
+ require 'dredd_hooks/definitions'
4
+
1
5
  module DreddHooks
2
- module Runner
3
6
 
7
+ # The Ruby hooks runner stores and runs the Ruby hooks
8
+ #
9
+ # It provides registration methods to be used from the DSL,
10
+ # as well as methods to run hooks by name from the server.
11
+ #
12
+ # All these methods are generated automatically according
13
+ # to the hooks definitions.
14
+ #
15
+ # Note that this class is a Singleton. Use Runner.instance to
16
+ # get references to its unique instance.
17
+ class Runner
18
+
19
+ include Singleton
20
+
21
+ # Define registration methods in the form of:
4
22
  #
5
- # Runers for Transaction specific hooks
23
+ # def register_before_hook(transction_name, &block)
24
+ # hooks = @before_hooks || {}
25
+ # transaction_hooks = hooks.fetch(transaction_name, [])
26
+ # transaction_hooks.push(block)
27
+ # hooks[transaction_name] = transaction_hooks
28
+ # @before_hooks = hooks
29
+ # end
6
30
  #
31
+ # Hooks names are defined by HOOKS_ON_SINGLE_TRANSACTIONS.
32
+ #
33
+ # Returns nothing.
34
+ def self.define_registration_methods_for_hooks_on_single_transactions
35
+ HOOKS_ON_SINGLE_TRANSACTIONS.each do |hook_name|
7
36
 
8
- def self.run_before_hooks_for_transaction transaction
9
- transaction_name = transaction["name"]
10
- hooks = Methods.class_variable_get("@@before_hooks")[transaction_name]
11
- if hooks.kind_of? Array
12
- hooks.each do |hook_proc|
13
- hook_proc.call transaction
37
+ define_method "register_#{hook_name}_hook" do |transaction_name, &block|
38
+ hooks = instance_variable_get("@#{hook_name}_hooks") || {}
39
+ transaction_hooks = hooks.fetch(transaction_name, [])
40
+ transaction_hooks.push(block)
41
+ hooks[transaction_name] = transaction_hooks
42
+ instance_variable_set("@#{hook_name}_hooks", hooks)
14
43
  end
15
- end
16
- return transaction
17
- end
18
44
 
19
- def self.run_before_validation_hooks_for_transaction transaction
20
- transaction_name = transaction["name"]
21
- hooks = Methods.class_variable_get("@@before_validation_hooks")[transaction_name]
22
- if hooks.kind_of? Array
23
- hooks.each do |hook_proc|
24
- hook_proc.call transaction
25
- end
26
45
  end
27
- return transaction
28
46
  end
47
+ private_class_method :define_registration_methods_for_hooks_on_single_transactions
29
48
 
30
- def self.run_after_hooks_for_transaction transaction
31
- transaction_name = transaction["name"]
32
- hooks = Methods.class_variable_get("@@after_hooks")[transaction_name]
33
- if hooks.kind_of? Array
34
- hooks.each do |hook_proc|
35
- hook_proc.call transaction
49
+ # Define registration methods in the form of:
50
+ #
51
+ # def register_before_all_hook(&block)
52
+ # hooks = @before_hooks || []
53
+ # hooks.push(block)
54
+ # @before_all_hooks = hooks
55
+ # end
56
+ #
57
+ # Hooks names are defined by HOOKS_ON_MULTIPLE_TRANSACTIONS.
58
+ #
59
+ # Returns nothing.
60
+ def self.define_registration_methods_for_hooks_on_multiple_transactions
61
+ HOOKS_ON_MULTIPLE_TRANSACTIONS.each do |hook_name|
62
+
63
+ define_method "register_#{hook_name}_hook" do |&block|
64
+ hooks = instance_variable_get("@#{hook_name}_hooks") || []
65
+ hooks.push(block)
66
+ instance_variable_set("@#{hook_name}_hooks", hooks)
36
67
  end
68
+
37
69
  end
38
- return transaction
39
70
  end
71
+ private_class_method :define_registration_methods_for_hooks_on_multiple_transactions
40
72
 
73
+ # Define runner methods in the form of:
41
74
  #
42
- # Runners for *_each hooks API
75
+ # def run_before_hooks_for_transaction(transaction)
76
+ # hooks = @before_hooks || {}
77
+ # transaction_name = transaction['name']
78
+ # transaction_hooks = hooks.fetch(transaction_name, [])
79
+ # transaction_hooks.each do |hook|
80
+ # hook.call(transaction)
81
+ # end
82
+ # return transaction
83
+ # end
43
84
  #
85
+ # Hooks names are defined by HOOKS_ON_SINGLE_TRANSACTIONS.
86
+ #
87
+ # Returns nothing.
88
+ def self.define_runners_for_hooks_on_single_transactions
89
+ HOOKS_ON_SINGLE_TRANSACTIONS.each do |hook_name|
44
90
 
45
- def self.run_before_each_hooks_for_transaction transaction
46
- Methods.class_variable_get("@@before_each_hooks").each do |hook_proc|
47
- hook_proc.call transaction
48
- end
49
- return transaction
50
- end
51
-
52
- def self.run_before_each_validation_hooks_for_transaction transaction
53
- Methods.class_variable_get("@@before_each_validation_hooks").each do |hook_proc|
54
- hook_proc.call transaction
55
- end
56
- return transaction
57
- end
91
+ define_method "run_#{hook_name}_hooks_for_transaction" do |transaction|
92
+ hooks = instance_variable_get("@#{hook_name}_hooks") || {}
93
+ transaction_name = transaction['name']
94
+ transaction_hooks = hooks.fetch(transaction_name, [])
95
+ transaction_hooks.each do |hook|
96
+ hook.call(transaction)
97
+ end
98
+ return transaction
99
+ end
58
100
 
59
- def self.run_after_each_hooks_for_transaction transaction
60
- Methods.class_variable_get("@@after_each_hooks").each do |hook_proc|
61
- hook_proc.call transaction
62
101
  end
63
- return transaction
64
102
  end
103
+ private_class_method :define_runners_for_hooks_on_single_transactions
65
104
 
105
+ # Define runner methods in the form of:
106
+ #
107
+ # def run_before_all_hooks_for_transaction(transaction)
108
+ # hooks = @before_all_hooks || []
109
+ # hooks.each do |hook|
110
+ # hook.call(transaction)
111
+ # end
112
+ # return transaction
113
+ # end
66
114
  #
67
- # Runners for *_all hooks API
115
+ # Hooks names are defined by HOOKS_ON_MULTIPLE_TRANSACTIONS.
68
116
  #
117
+ # Returns nothing.
118
+ def self.define_runners_for_hooks_on_multiple_transactions
119
+ HOOKS_ON_MULTIPLE_TRANSACTIONS.each do |hook_name|
69
120
 
70
- def self.run_before_all_hooks_for_transactions transactions
71
- Methods.class_variable_get("@@before_all_hooks").each do |hook_proc|
72
- hook_proc.call transactions
73
- end
74
- return transactions
75
- end
121
+ define_method "run_#{hook_name}_hooks_for_transaction" do |transaction|
122
+ hooks = instance_variable_get("@#{hook_name}_hooks") || []
123
+ hooks.each do |hook|
124
+ hook.call(transaction)
125
+ end
126
+ return transaction
127
+ end
76
128
 
77
- def self.run_after_all_hooks_for_transactions transactions
78
- Methods.class_variable_get("@@after_all_hooks").each do |hook_proc|
79
- hook_proc.call transactions
80
129
  end
81
- return transactions
82
130
  end
131
+ private_class_method :define_runners_for_hooks_on_multiple_transactions
132
+
133
+ define_registration_methods_for_hooks_on_single_transactions
134
+ define_registration_methods_for_hooks_on_multiple_transactions
135
+
136
+ define_runners_for_hooks_on_single_transactions
137
+ define_runners_for_hooks_on_multiple_transactions
138
+
83
139
  end
84
- end
140
+ end
141
+
@@ -1,86 +1,76 @@
1
1
  require 'socket'
2
- require 'json'
2
+
3
+ require 'dredd_hooks/server/buffer'
4
+ require 'dredd_hooks/server/events_handler'
3
5
 
4
6
  module DreddHooks
7
+
8
+ # The hooks worker server
5
9
  class Server
6
- #
7
- # The hooks worker server
8
- #
10
+
11
+ attr_reader :buffer, :error, :events_handler, :out, :server
12
+ private :buffer, :error, :events_handler, :out, :server
9
13
 
10
14
  HOST = '127.0.0.1'
11
15
  PORT = 61321
12
16
  MESSAGE_DELIMITER = "\n"
13
17
 
14
- @server = nil
15
-
16
- def process_message message, client
17
- event = message['event']
18
- data = message['data']
19
-
20
- if event == "beforeEach"
21
- data = DreddHooks::Runner.run_before_each_hooks_for_transaction data
22
- data = DreddHooks::Runner.run_before_hooks_for_transaction data
23
- end
24
-
25
- if event == "beforeEachValidation"
26
- data = DreddHooks::Runner.run_before_each_validation_hooks_for_transaction data
27
- data = DreddHooks::Runner.run_before_validation_hooks_for_transaction data
28
- end
29
-
30
- if event == "afterEach"
31
- data = DreddHooks::Runner.run_after_hooks_for_transaction data
32
- data = DreddHooks::Runner.run_after_each_hooks_for_transaction data
33
- end
34
-
35
- if event == "beforeAll"
36
- data = DreddHooks::Runner.run_before_all_hooks_for_transactions data
37
- end
38
-
39
- if event == "afterAll"
40
- data = DreddHooks::Runner.run_after_all_hooks_for_transactions data
41
- end
42
-
43
- to_send = {
44
- "uuid" => message['uuid'],
45
- "event" => event,
46
- "data" => data
47
- }.to_json
48
- client.puts to_send + "\n"
18
+ def initialize(error=STDERR, out=STDOUT)
19
+ @error = error
20
+ @out = out
21
+ @server = TCPServer.new(HOST, PORT)
22
+ @buffer = Buffer.new(MESSAGE_DELIMITER)
23
+ @events_handler = EventsHandler.new
49
24
  end
50
25
 
51
26
  def run
52
- @server = TCPServer.new HOST, PORT
27
+ disable_buffering(out)
53
28
  loop do
54
- #Thread.abort_on_exception=true
55
- client = @server.accept
56
- STDERR.puts 'Dredd connected to Ruby Dredd hooks worker'
57
- buffer = ""
29
+ client = server.accept
30
+ out.puts 'Dredd connected to Ruby Dredd hooks worker'
31
+ buffer.flush!
58
32
  while (data = client.recv(10))
59
- buffer += data
60
- if buffer.include? MESSAGE_DELIMITER
61
- splitted_buffer = buffer.split(MESSAGE_DELIMITER)
62
- buffer = ""
63
-
64
- messages = []
65
-
66
- splitted_buffer.each do |message|
67
- begin
68
- messages.push JSON.parse(message)
69
-
70
- rescue JSON::ParserError
71
- # if message aftger delimiter is not parseable json, it's
72
- # a chunk of next message, put it back to the buffer
73
- buffer += message
74
- end
75
- end
33
+ buffer << data
34
+ if buffer.any_message?
35
+ messages = buffer.unshift_messages
76
36
 
77
37
  messages.each do |message|
78
- process_message message, client
38
+ response = process_message(message)
39
+ client.puts response + MESSAGE_DELIMITER
79
40
  end
80
41
  end
81
42
  end
82
43
  client.close
83
44
  end
84
45
  end
46
+
47
+ private
48
+
49
+ # Write to a file (e.g. STDOUT) without delay
50
+ #
51
+ # See https://stackoverflow.com/q/23001033
52
+ # and http://ruby-doc.org/core-2.3.1/IO.html#method-i-sync-3D
53
+ def disable_buffering(file)
54
+ file.sync = true
55
+ end
56
+
57
+ def process_message(message)
58
+ event = message['event']
59
+ transaction = message['data']
60
+
61
+ transaction = events_handler.handle(event, transaction)
62
+
63
+ response(message['uuid'], event, transaction)
64
+ end
65
+
66
+ def response(message_uuid, event, transaction)
67
+ {
68
+ uuid: message_uuid,
69
+ event: event,
70
+ data: transaction,
71
+ }.to_json
72
+ end
73
+
85
74
  end
86
- end
75
+ end
76
+