sapience 0.2.4 → 0.2.5

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +21 -0
  3. data/.simplecov +19 -16
  4. data/.travis.yml +3 -3
  5. data/CHANGELOG.md +4 -0
  6. data/Gemfile +0 -8
  7. data/README.md +5 -0
  8. data/config/default.yml +4 -0
  9. data/docker-compose.yml +14 -0
  10. data/lib/sapience/appender/stream.rb +0 -1
  11. data/lib/sapience/base.rb +34 -4
  12. data/lib/sapience/configuration.rb +41 -20
  13. data/lib/sapience/core_ext/hash.rb +10 -7
  14. data/lib/sapience/core_ext/symbol.rb +15 -0
  15. data/lib/sapience/core_ext/thread.rb +1 -0
  16. data/lib/sapience/extensions/action_cable/tagged_logger_proxy.rb +2 -0
  17. data/lib/sapience/extensions/action_controller/live.rb +2 -0
  18. data/lib/sapience/extensions/action_controller/log_subscriber.rb +76 -121
  19. data/lib/sapience/extensions/action_dispatch/debug_exceptions.rb +2 -0
  20. data/lib/sapience/extensions/action_view/log_subscriber.rb +16 -6
  21. data/lib/sapience/extensions/action_view/streaming_template_renderer.rb +2 -0
  22. data/lib/sapience/extensions/active_job/logging.rb +1 -1
  23. data/lib/sapience/extensions/active_model_serializers/logging.rb +7 -2
  24. data/lib/sapience/extensions/active_record/log_subscriber.rb +45 -29
  25. data/lib/sapience/extensions/rails/rack/logger.rb +1 -0
  26. data/lib/sapience/extensions/rails/rack/logger_info_as_debug.rb +2 -0
  27. data/lib/sapience/formatters/color.rb +0 -1
  28. data/lib/sapience/formatters/default.rb +0 -1
  29. data/lib/sapience/formatters/json.rb +0 -1
  30. data/lib/sapience/formatters/raw.rb +0 -1
  31. data/lib/sapience/log.rb +54 -35
  32. data/lib/sapience/logger.rb +50 -71
  33. data/lib/sapience/rails.rb +17 -20
  34. data/lib/sapience/sapience.rb +23 -27
  35. data/lib/sapience/subscriber.rb +1 -13
  36. data/lib/sapience/version.rb +1 -1
  37. data/lib/sapience.rb +4 -3
  38. data/sapience.gemspec +6 -1
  39. data/test_app/Gemfile +7 -0
  40. data/test_app/Rakefile +2 -0
  41. data/test_app/app/models/post.rb +1 -1
  42. data/test_app/app/views/posts/_form.html.slim +18 -0
  43. data/test_app/app/views/posts/edit.html.slim +8 -0
  44. data/test_app/app/views/posts/index.html.slim +25 -0
  45. data/test_app/app/views/posts/new.html.slim +5 -0
  46. data/test_app/app/views/posts/show.html.slim +15 -0
  47. data/test_app/app/workers/test_worker.rb +17 -0
  48. data/test_app/bin/sneakers +10 -0
  49. data/test_app/config/initializers/sneakers.rb +15 -0
  50. data/test_app/config/sapience_example.yml +24 -0
  51. data/test_app/db/migrate/{20160812093621_create_posts.rb → 20160902141445_create_posts.rb} +1 -1
  52. data/test_app/db/schema.rb +1 -1
  53. data/test_app/lib/external_sneaker.rb +46 -0
  54. data/test_app/spec/factories/posts.rb +7 -0
  55. data/test_app/spec/factories/users.rb +8 -0
  56. data/test_app/spec/rails_helper.rb +8 -3
  57. data/test_app/spec/requests/posts_spec.rb +2 -1
  58. data/test_app/spec/views/posts/edit.html.slim_spec.rb +17 -0
  59. data/test_app/spec/views/posts/index.html.slim_spec.rb +17 -0
  60. data/test_app/spec/views/posts/new.html.slim_spec.rb +17 -0
  61. data/test_app/spec/views/posts/show.html.slim_spec.rb +14 -0
  62. data/test_app/spec/workers/test_worker_spec.rb +36 -0
  63. data/test_app.simplecov +19 -0
  64. metadata +95 -15
  65. data/.coveralls.yml +0 -1
  66. data/lib/sapience/extensions/action_controller/log_subscriber_processing.rb +0 -24
  67. data/test_app/app/views/posts/_form.html.erb +0 -32
  68. data/test_app/app/views/posts/create.html.erb +0 -2
  69. data/test_app/app/views/posts/destroy.html.erb +0 -2
  70. data/test_app/app/views/posts/edit.html.erb +0 -6
  71. data/test_app/app/views/posts/index.html.erb +0 -31
  72. data/test_app/app/views/posts/new.html.erb +0 -5
  73. data/test_app/app/views/posts/show.html.erb +0 -19
  74. data/test_app/app/views/posts/update.html.erb +0 -2
@@ -7,31 +7,6 @@ module Sapience
7
7
  class Logger < Base # rubocop:disable ClassLength, ClassVars
8
8
  include Sapience::Concerns::Compatibility
9
9
 
10
- # Returns a Logger instance
11
- #
12
- # Return the logger for a specific class, supports class specific log levels
13
- # logger = Sapience::Logger.new(self)
14
- # OR
15
- # logger = Sapience::Logger.new('MyClass')
16
- #
17
- # Parameters:
18
- # application
19
- # A class, module or a string with the application/class name
20
- # to be used in the logger
21
- #
22
- # level
23
- # The initial log level to start with for this logger instance
24
- # Default: Sapience.config.default_level
25
- #
26
- # filter [Regexp|Proc]
27
- # RegExp: Only include log messages where the class name matches the supplied
28
- # regular expression. All other messages will be ignored
29
- # Proc: Only include log messages where the supplied Proc returns true
30
- # The Proc must return true or false
31
- def initialize(klass, level = nil, filter = nil)
32
- super
33
- end
34
-
35
10
  # Flush all queued log entries disk, database, etc.
36
11
  # All queued log messages are written and then each appender is flushed in turn
37
12
  def self.flush # rubocop:disable AbcSize
@@ -73,51 +48,6 @@ module Sapience
73
48
  Sapience.remove_appender(appender)
74
49
  end
75
50
 
76
- @@lag_check_interval = 5000
77
- @@lag_threshold_s = 30
78
-
79
- # Returns the check_interval which is the number of messages between checks
80
- # to determine if the appender thread is falling behind
81
- def self.lag_check_interval
82
- @@lag_check_interval
83
- end
84
-
85
- # Set the check_interval which is the number of messages between checks
86
- # to determine if the appender thread is falling behind
87
- def self.lag_check_interval=(lag_check_interval)
88
- @@lag_check_interval = lag_check_interval
89
- end
90
-
91
- # Returns the amount of time in seconds
92
- # to determine if the appender thread is falling behind
93
- def self.lag_threshold_s
94
- @@lag_threshold_s
95
- end
96
-
97
- # Allow the internal logger to be overridden from its default to STDERR
98
- # Can be replaced with another Ruby logger or Rails logger, but never to
99
- # Sapience::Logger itself since it is for reporting problems
100
- # while trying to log to the various appenders
101
- def self.logger=(logger)
102
- @@logger = logger
103
- end
104
-
105
- # Place log request on the queue for the Appender thread to write to each
106
- # appender in the order that they were registered
107
- def log(log, message = nil, progname = nil, &block)
108
- # Compatibility with ::Logger
109
- return add(log, message, progname, &block) unless log.is_a?(Sapience::Log)
110
- @@appender_thread << lambda do
111
- Sapience.appenders.each do |appender|
112
- begin
113
- appender.log(log)
114
- rescue StandardError => exc
115
- logger.error "Appender thread: Failed to log to appender: #{appender.inspect}", exc
116
- end
117
- end
118
- end if @@appender_thread
119
- end
120
-
121
51
  @@appender_thread = nil
122
52
 
123
53
  # Internal logger for Sapience
@@ -135,7 +65,7 @@ module Sapience
135
65
  def self.start_appender_thread
136
66
  return false if appender_thread_active?
137
67
 
138
- @@appender_thread = Concurrent::SingleThreadExecutor.new
68
+ @@appender_thread = Sapience.log_executor_class.new
139
69
  fail "Failed to start Appender Thread" unless @@appender_thread
140
70
  true
141
71
  end
@@ -151,6 +81,55 @@ module Sapience
151
81
  def self.appender_thread
152
82
  @@appender_thread
153
83
  end
84
+
85
+ # Allow the internal logger to be overridden from its default to STDERR
86
+ # Can be replaced with another Ruby logger or Rails logger, but never to
87
+ # Sapience::Logger itself since it is for reporting problems
88
+ # while trying to log to the various appenders
89
+ def self.logger=(logger)
90
+ @@logger = logger
91
+ end
92
+
93
+ # Returns a Logger instance
94
+ #
95
+ # Return the logger for a specific class, supports class specific log levels
96
+ # logger = Sapience::Logger.new(self)
97
+ # OR
98
+ # logger = Sapience::Logger.new('MyClass')
99
+ #
100
+ # Parameters:
101
+ # application
102
+ # A class, module or a string with the application/class name
103
+ # to be used in the logger
104
+ #
105
+ # level
106
+ # The initial log level to start with for this logger instance
107
+ # Default: Sapience.config.default_level
108
+ #
109
+ # filter [Regexp|Proc]
110
+ # RegExp: Only include log messages where the class name matches the supplied
111
+ # regular expression. All other messages will be ignored
112
+ # Proc: Only include log messages where the supplied Proc returns true
113
+ # The Proc must return true or false
114
+ def initialize(klass, level = nil, filter = nil)
115
+ super
116
+ end
117
+
118
+ # Place log request on the queue for the Appender thread to write to each
119
+ # appender in the order that they were registered
120
+ def log(log, message = nil, progname = nil, &block)
121
+ # Compatibility with ::Logger
122
+ return add(log, message, progname, &block) unless log.is_a?(Sapience::Log)
123
+ @@appender_thread << lambda do
124
+ Sapience.appenders.each do |appender|
125
+ begin
126
+ appender.log(log)
127
+ rescue StandardError => exc
128
+ self.class.logger.error "Appender thread: Failed to log to appender: #{appender.inspect}", exc
129
+ end
130
+ end
131
+ end if @@appender_thread
132
+ end
154
133
  # rubocop:enable BlockNesting, AssignmentInCondition, PerceivedComplexity, CyclomaticComplexity, AbcSize, LineLength, RescueException
155
134
  end
156
135
  end
@@ -1,4 +1,15 @@
1
1
  require "sapience"
2
+ require "sapience/extensions/action_cable/tagged_logger_proxy"
3
+ require "sapience/extensions/action_controller/live"
4
+ require "sapience/extensions/action_controller/log_subscriber"
5
+ require "sapience/extensions/action_dispatch/debug_exceptions"
6
+ require "sapience/extensions/action_view/streaming_template_renderer"
7
+ require "sapience/extensions/active_job/logging"
8
+ require "sapience/extensions/active_model_serializers/logging"
9
+ require "sapience/extensions/active_record/log_subscriber"
10
+ require "sapience/extensions/rails/rack/logger"
11
+ require "sapience/extensions/rails/rack/logger_info_as_debug"
12
+ require "sapience/extensions/action_view/log_subscriber"
2
13
 
3
14
  module Sapience
4
15
  class Rails < ::Rails::Engine
@@ -35,38 +46,24 @@ module Sapience
35
46
  Raven.send(:include) { Sapience::Loggable }
36
47
 
37
48
  # Replace the Sneakers logger
38
- Sneakers.logger = Sapience[Sneakers] if defined?(Sneakers)
49
+ Sneakers.configure(log: Sapience[Sneakers]) if defined?(Sneakers)
39
50
 
40
51
  # Replace the Bugsnag logger
41
52
  Bugsnag.configure { |config| config.logger = Sapience[Bugsnag] } if defined?(Bugsnag)
42
53
 
43
54
  # Set the logger for concurrent-ruby
44
55
  Concurrent.global_logger = Sapience[Concurrent] if defined?(Concurrent)
45
-
46
- # Rails Patches
47
- Kernel.require "sapience/extensions/action_cable/tagged_logger_proxy" if defined?(ActionCable)
48
- Kernel.require "sapience/extensions/action_controller/live" if defined?(ActionController::Live)
49
- Kernel.require "sapience/extensions/action_dispatch/debug_exceptions" if defined?(ActionDispatch::DebugExceptions)
50
- if defined?(ActionView::StreamingTemplateRenderer::Body)
51
- Kernel.require "sapience/extensions/action_view/streaming_template_renderer"
52
- end
53
- Kernel.require "sapience/extensions/active_job/logging" if defined?(ActiveJob)
54
- Kernel.require "sapience/extensions/active_model_serializers/logging" if defined?(ActiveModelSerializers)
55
- Kernel.require "sapience/extensions/action_controller/log_subscriber" if defined?(ActionController)
56
- Kernel.require "sapience/extensions/active_record/log_subscriber" if defined?(ActiveRecord::LogSubscriber)
57
- Kernel.require "sapience/extensions/rails/rack/logger" if defined?(::Rails::Rack::Logger)
58
- Kernel.require "sapience/extensions/rails/rack/logger_info_as_debug" if defined?(::Rails::Rack::Logger)
59
- Kernel.require "sapience/extensions/action_view/log_subscriber" if defined?(ActionView::LogSubscriber)
60
- if defined?(ActionView::LogSubscriber)
61
- Kernel.require "sapience/extensions/action_controller/log_subscriber_processing"
62
- end
63
56
  end
64
57
 
65
58
  # Before any initializers run, but after the gems have been loaded
66
59
  config.after_initialize do
67
60
  # Replace the Bugsnag logger
68
61
  Bugsnag.configure { |config| config.logger = Sapience[Bugsnag] } if defined?(Bugsnag)
62
+ Sapience::Extensions::ActionController::LogSubscriber.attach_to :action_controller
63
+ # Sapience::Extensions::ActiveSupport::MailerLogSubscriber.attach_to :action_mailer
64
+ Sapience::Extensions::ActiveRecord::LogSubscriber.attach_to :active_record
65
+ Sapience::Extensions::ActionView::LogSubscriber.attach_to :action_view
66
+ # Sapience::Extensions::ActiveJob::LogSubscriber.attach_to :active_job
69
67
  end
70
-
71
68
  end
72
69
  end
@@ -1,6 +1,7 @@
1
1
  require "concurrent"
2
2
  require "socket"
3
3
  require "sapience/descendants"
4
+ require "English"
4
5
 
5
6
  # Example:
6
7
  #
@@ -19,12 +20,16 @@ require "sapience/descendants"
19
20
 
20
21
  # rubocop:disable ClassVars
21
22
  module Sapience
23
+ UnknownClass = Class.new(NameError)
22
24
  @@configured = nil
23
25
 
24
26
  # Logging levels in order of most detailed to most severe
25
27
  LEVELS = [:trace, :debug, :info, :warn, :error, :fatal].freeze
26
28
  DEFAULT_ENV = "default".freeze
27
29
 
30
+ # TODO: Should we really always read from file?
31
+ # What if someone wants to configure sapience with a block
32
+ # without reading the default.yml?
28
33
  def self.config
29
34
  @@config ||= begin
30
35
  config = ConfigLoader.load_from_file
@@ -48,6 +53,7 @@ module Sapience
48
53
  @@logger = nil
49
54
  @@metrix = nil
50
55
  @@configured = nil
56
+ clear_tags!
51
57
  reset_appenders!
52
58
  end
53
59
 
@@ -68,6 +74,8 @@ module Sapience
68
74
  end
69
75
  end
70
76
 
77
+ # TODO: Maybe when configuring with a block we should create a new config?
78
+ # See the TODO note on .config for more information
71
79
  def self.configure(force: false)
72
80
  yield config if block_given?
73
81
  return config if configured? && force == false
@@ -162,7 +170,7 @@ module Sapience
162
170
  # logger.debug("Login time", user: 'Joe', duration: 100, ip_address: '127.0.0.1')
163
171
  def self.add_appender(appender, options = {}, _deprecated_level = nil, &_block)
164
172
  fail ArgumentError, "options should be a hash" unless options.is_a?(Hash)
165
- options.deep_symbolize_keys!
173
+ options.deep_symbolize_keyz!
166
174
  appender_class = constantize_symbol(appender)
167
175
  validate_appender!(appender_class)
168
176
 
@@ -273,19 +281,6 @@ module Sapience
273
281
  Thread.current[:sapience_tags].pop
274
282
  end
275
283
 
276
- # Add the supplied named tags to the list of tags to log for this thread whilst
277
- # the supplied block is active.
278
- #
279
- # Returns result of block
280
- #
281
- # Example:
282
- def self.named_tags(tag)
283
- (Thread.current[:sapience_tags] ||= []) << tag
284
- yield
285
- ensure
286
- Thread.current[:sapience_tags].pop
287
- end
288
-
289
284
  # Add the supplied tags to the list of tags to log for this thread whilst
290
285
  # the supplied block is active.
291
286
  # Returns result of block
@@ -314,6 +309,10 @@ module Sapience
314
309
  new_tags
315
310
  end
316
311
 
312
+ def self.clear_tags!
313
+ Thread.current[:sapience_tags] = []
314
+ end
315
+
317
316
  # Remove specified number of tags from the current tag list
318
317
  def self.pop_tags(quantity = 1)
319
318
  t = Thread.current[:sapience_tags]
@@ -366,11 +365,13 @@ module Sapience
366
365
 
367
366
  reset_appenders!
368
367
 
368
+ def self.log_executor_class
369
+ constantize_symbol(config.log_executor, "Concurrent")
370
+ end
371
+
369
372
  def self.constantize_symbol(symbol, namespace = "Sapience::Appender")
370
- klass = "#{namespace}::#{camelize(symbol.to_s)}"
371
- constantize(klass)
372
- rescue NameError
373
- raise(ArgumentError, "Could not convert symbol: #{symbol} to a class in: #{namespace}. Looking for: #{klass}")
373
+ class_name = "#{namespace}::#{symbol.camelize}"
374
+ constantize(class_name)
374
375
  end
375
376
 
376
377
  def self.constantize(class_name)
@@ -380,16 +381,11 @@ module Sapience
380
381
  else
381
382
  class_name.split("::").inject(Object) { |o, name| o.const_get(name) } # rubocop:disable SingleLineBlockParams
382
383
  end
384
+ rescue NameError
385
+ raise UnknownClass, "Could not find class: #{class_name}."
383
386
  end
384
387
 
385
- # Borrow from Rails, when not running Rails
386
- def self.camelize(term) # rubocop:disable AbcSize
387
- string = term.to_s
388
- string = string.sub(/^[a-z\d]*/) { |match| match.capitalize }
389
- string.gsub!(/(?:_|(\/))([a-z\d]*)/i) do
390
- "#{Regexp.last_match[1]}#{inflections.acronyms[Regexp.last_match[2]] || Regexp.last_match[2].capitalize}"
391
- end
392
- string.gsub!("/".freeze, "::".freeze)
393
- string
388
+ def self.root
389
+ @_root ||= Gem::Specification.find_by_name("sapience").gem_dir
394
390
  end
395
391
  end
@@ -105,9 +105,7 @@ module Sapience
105
105
  # rubocop:disable CyclomaticComplexity, AbcSize, PerceivedComplexity
106
106
  def extract_formatter(formatter, &block)
107
107
  case
108
- when formatter.is_a?(Symbol)
109
- Sapience.constantize_symbol(formatter, "Sapience::Formatters").new
110
- when formatter.is_a?(String)
108
+ when formatter.is_a?(Symbol) || formatter.is_a?(String)
111
109
  Sapience.constantize_symbol(formatter, "Sapience::Formatters").new
112
110
  when formatter.is_a?(Hash) && formatter.size > 0
113
111
  fmt, options = formatter.first
@@ -123,15 +121,5 @@ module Sapience
123
121
  end
124
122
  end
125
123
  # rubocop:enable CyclomaticComplexity, AbcSize, PerceivedComplexity
126
-
127
- SUBSCRIBER_OPTIONS = [:level, :formatter, :filter, :application, :host].freeze
128
-
129
- # Returns [Hash] the subscriber common options from the supplied Hash
130
- def extract_subscriber_options!(options)
131
- subscriber_options = {}
132
- SUBSCRIBER_OPTIONS.each { |key| subscriber_options[key] = options.delete(key) if options.key?(key) }
133
- subscriber_options
134
- end
135
-
136
124
  end
137
125
  end
@@ -1,3 +1,3 @@
1
1
  module Sapience
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
  end
data/lib/sapience.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  require "sapience/version"
2
+ require "sapience/ansi_colors"
3
+ require "sapience/core_ext/hash"
4
+ require "sapience/core_ext/symbol"
5
+ require "sapience/core_ext/thread"
2
6
  require "sapience/sapience"
3
7
 
4
8
  # @formatter:off
@@ -14,9 +18,6 @@ require "sapience/formatters/json"
14
18
  require "sapience/config_loader"
15
19
  require "sapience/configuration"
16
20
  require "sapience/configuration/grape"
17
- require "sapience/ansi_colors"
18
- require "sapience/core_ext/hash"
19
- require "sapience/core_ext/thread"
20
21
  require "sapience/base"
21
22
  require "sapience/log"
22
23
  require "sapience/logger"
data/sapience.gemspec CHANGED
@@ -36,7 +36,12 @@ Gem::Specification.new do |spec|
36
36
  spec.add_development_dependency "simplecov"
37
37
  spec.add_development_dependency "simplecov-json"
38
38
  spec.add_development_dependency "rspec-its"
39
+ spec.add_development_dependency "pry-nav"
40
+ spec.add_development_dependency "sentry-raven"
41
+ spec.add_development_dependency "dogstatsd-ruby"
42
+ spec.add_development_dependency "rails", "~> 5.0.0.1"
43
+ spec.add_development_dependency "grape"
44
+ spec.add_development_dependency "active_model_serializers", "~> 0.10.0"
39
45
  spec.add_development_dependency "codeclimate-test-reporter"
40
- spec.add_development_dependency "coveralls"
41
46
  spec.add_development_dependency "gem-release"
42
47
  end
data/test_app/Gemfile CHANGED
@@ -17,6 +17,9 @@ gem "puma", "~> 3.0"
17
17
  gem "sapience", path: "../", require: "sapience/rails"
18
18
  gem "sentry-raven"
19
19
  gem "statsd-ruby"
20
+ gem "sneakers"
21
+ gem "slim-rails"
22
+ gem "active_model_serializers"
20
23
 
21
24
  group :development, :test do
22
25
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
@@ -24,6 +27,7 @@ group :development, :test do
24
27
  # gem "pry-nav"
25
28
  gem "pry-byebug"
26
29
  gem "rspec-rails"
30
+ gem "factory_girl_rails"
27
31
  end
28
32
 
29
33
  group :development do
@@ -34,6 +38,9 @@ end
34
38
 
35
39
  group :test do
36
40
  gem "rspec-its"
41
+ gem "bunny-mock"
42
+ gem "rspec-wait"
43
+ gem "rails-controller-testing"
37
44
  end
38
45
 
39
46
  # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
data/test_app/Rakefile CHANGED
@@ -4,6 +4,8 @@ require_relative "config/application"
4
4
 
5
5
  Rails.application.load_tasks
6
6
 
7
+ require "sneakers/tasks"
8
+
7
9
  require "rspec/core/rake_task"
8
10
  RSpec::Core::RakeTask.new(:spec)
9
11
 
@@ -1,3 +1,3 @@
1
1
  class Post < ApplicationRecord
2
- belongs_to :author
2
+ belongs_to :author, class_name: User
3
3
  end
@@ -0,0 +1,18 @@
1
+ = form_for @post do |f|
2
+ - if @post.errors.any?
3
+ #error_explanation
4
+ h2 = "#{pluralize(@post.errors.count, "error")} prohibited this post from being saved:"
5
+ ul
6
+ - @post.errors.full_messages.each do |message|
7
+ li = message
8
+
9
+ .field
10
+ = f.label :title
11
+ = f.text_field :title
12
+ .field
13
+ = f.label :body
14
+ = f.text_field :body
15
+ .field
16
+ = f.label :author
17
+ = f.text_field :author
18
+ .actions = f.submit
@@ -0,0 +1,8 @@
1
+ h1 Editing post
2
+
3
+ == render 'form'
4
+
5
+ = link_to 'Show', @post
6
+ '|
7
+ = link_to 'Back', posts_path
8
+
@@ -0,0 +1,25 @@
1
+ h1 Listing posts
2
+
3
+ table
4
+ thead
5
+ tr
6
+ th Title
7
+ th Body
8
+ th Author
9
+ th
10
+ th
11
+ th
12
+
13
+ tbody
14
+ - @posts.each do |post|
15
+ tr
16
+ td = post.title
17
+ td = post.body
18
+ td = post.author
19
+ td = link_to 'Show', post
20
+ td = link_to 'Edit', edit_post_path(post)
21
+ td = link_to 'Destroy', post, data: { confirm: 'Are you sure?' }, method: :delete
22
+
23
+ br
24
+
25
+ = link_to 'New Post', new_post_path
@@ -0,0 +1,5 @@
1
+ h1 New post
2
+
3
+ == render 'form'
4
+
5
+ = link_to 'Back', posts_path
@@ -0,0 +1,15 @@
1
+ p#notice = notice
2
+
3
+ p
4
+ strong Title:
5
+ = @post.title
6
+ p
7
+ strong Body:
8
+ = @post.body
9
+ p
10
+ strong Author:
11
+ = @post.author
12
+
13
+ = link_to 'Edit', edit_post_path(@post)
14
+ '|
15
+ = link_to 'Back', posts_path
@@ -0,0 +1,17 @@
1
+ require_relative "../../../spec/support/file_helper"
2
+
3
+ class TestWorker
4
+ QUEUE_NAME = :sneakers_queue
5
+ ROUTING_KEY = :sneakers_routing_key
6
+ VERIFICATION_FILE = "tmp/sneakers.verified".freeze
7
+
8
+ include Sneakers::Worker
9
+ include FileHelper
10
+
11
+ from_queue QUEUE_NAME, routing_key: ROUTING_KEY
12
+
13
+ def work(_message)
14
+ create_file(VERIFICATION_FILE)
15
+ ack!
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ require "bundler/setup"
3
+ require "serverengine"
4
+ require "sneakers"
5
+ require "sneakers/runner"
6
+ require_relative "../app/workers/test_worker"
7
+ require_relative "../config/initializers/sneakers"
8
+
9
+ runner = Sneakers::Runner.new([TestWorker])
10
+ runner.run
@@ -0,0 +1,15 @@
1
+ require "serverengine"
2
+ require "sneakers"
3
+
4
+ p ENV.fetch("AMQP") { "amqp://guest:guest@localhost:5672" }
5
+
6
+ Sneakers.configure(
7
+ amqp: ENV.fetch("AMQP") { "amqp://guest:guest@localhost:5672" },
8
+ exchange_type: :direct,
9
+ log: Sapience[Sneakers], # Log file
10
+ exchange: "sapience", # AMQP exchange
11
+ durable: false, # Is queue durable?
12
+ ack: true, # Must we acknowledge?
13
+ metrics: Sapience.metrix,
14
+ )
15
+ Sapience.logger.level = Logger::DEBUG
@@ -0,0 +1,24 @@
1
+ ---
2
+ default:
3
+ log_level: error
4
+ appenders:
5
+ - stream:
6
+ file_name: log/error.log
7
+ formatter: default
8
+
9
+ development:
10
+ log_level: debug
11
+ appenders:
12
+ - stream:
13
+ io: STDOUT
14
+ formatter: color
15
+ - stream:
16
+ file_name: log/development.log
17
+ formatter: color
18
+
19
+ test:
20
+ log_level: fatal
21
+ appenders:
22
+ - stream:
23
+ file_name: log/fatal.log
24
+ formatter: json
@@ -3,7 +3,7 @@ class CreatePosts < ActiveRecord::Migration[5.0]
3
3
  create_table :posts do |t|
4
4
  t.string :title
5
5
  t.string :body
6
- t.belongs_to :author, foreign_key: { name: :posts_users_fk }
6
+ t.belongs_to :author, foreign_key: true
7
7
 
8
8
  t.timestamps
9
9
  end
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 20160812093621) do
13
+ ActiveRecord::Schema.define(version: 20160902141445) do
14
14
 
15
15
  create_table "posts", force: :cascade do |t|
16
16
  t.string "title"
@@ -0,0 +1,46 @@
1
+ require "timeout"
2
+
3
+ class ExternalSneaker
4
+ attr_accessor :worker_pid, :start_command
5
+
6
+ def initialize(start_command)
7
+ fail ArgumentError, "start_command was expected" if start_command.nil?
8
+
9
+ self.start_command = start_command
10
+ end
11
+
12
+ def start
13
+ puts "Trying to start #{start_command}..."
14
+ self.worker_pid = fork do
15
+ start_child
16
+ end
17
+
18
+ at_exit do
19
+ stop_child
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def start_child
26
+ exec({ "RAILS_ENV" => Rails.env, "WORKERS" => "TestWorker" }, start_command)
27
+ end
28
+
29
+ def stop_child # rubocop:disable AbcSize
30
+ puts "Trying to stop #{start_command}, pid: #{worker_pid}"
31
+
32
+ # send TERM and wait for exit
33
+ Process.kill("TERM", worker_pid)
34
+
35
+ begin
36
+ Timeout.timeout(10) do
37
+ Process.waitpid(worker_pid)
38
+ puts "Process #{start_command} stopped successfully"
39
+ end
40
+ rescue Timeout::Error
41
+ # Kill process if could not exit in 10 seconds
42
+ puts "Sending KILL signal to #{start_command}, pid: #{worker_pid}"
43
+ Process.kill("KILL", worker_pid)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,7 @@
1
+ FactoryGirl.define do
2
+ factory :post do
3
+ title "This is a post"
4
+ body "It has a lot of content"
5
+ association :author, factory: :user
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ FactoryGirl.define do
2
+ sequence(:username) { |i| "mrcool#{i}" }
3
+ sequence(:email) { |i| "so#{i}@cool.com" }
4
+ factory :user do
5
+ username
6
+ email
7
+ end
8
+ end