sapience 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
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