loggability 0.7.0 → 0.8.0.pre.65

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: 4cd7d81cde7a350d212b84b58c36a2b83d235da4
4
- data.tar.gz: 5320e44d3b6264f03c5f524bd9791cdd8837342a
3
+ metadata.gz: 080af7dac1d884020028cd90faa021b2162279ed
4
+ data.tar.gz: 5030296da798cc5802812a0b1a7fcee1223161b7
5
5
  SHA512:
6
- metadata.gz: 22ec6cf0983afc06ddbaa7d26db5fc1684fbfc4c8ce11f688ef64501da200d49b94607b43b9d84431985d49b9655361054b76c1ab981ce650857c51db78f69de
7
- data.tar.gz: 3047401b261320512aa47dcd2d839648df9abc2a1def4b8bb3181efe957a09bd988ad0d8fe66198e125aa776fad87fb995a0190d9cd58119327c9a78df669958
6
+ metadata.gz: eed60ff758345f3996dd7ad517bbb4de4ea4d52ff8a4520eeaa380e01e1244df5cddf71784b76a5cf6dfc529a74a2a9c411823317b8cea28743f44020a6c4338
7
+ data.tar.gz: c65f9e7137429f584aad8cba285b437793df9461c977b36ab34c44e595b7306f9ef457c2db1347c080742c01add876c313476c66b58da6ede67916696b714072
checksums.yaml.gz.sig CHANGED
Binary file
data/Manifest.txt CHANGED
@@ -9,11 +9,15 @@ lib/loggability/formatter.rb
9
9
  lib/loggability/formatter/color.rb
10
10
  lib/loggability/formatter/default.rb
11
11
  lib/loggability/formatter/html.rb
12
+ lib/loggability/logclient.rb
12
13
  lib/loggability/logger.rb
14
+ lib/loggability/loghost.rb
15
+ lib/loggability/override.rb
13
16
  lib/loggability/spechelpers.rb
14
- spec/lib/helpers.rb
17
+ spec/helpers.rb
15
18
  spec/loggability/formatter/color_spec.rb
16
19
  spec/loggability/formatter/html_spec.rb
17
20
  spec/loggability/formatter_spec.rb
18
21
  spec/loggability/logger_spec.rb
22
+ spec/loggability/override_spec.rb
19
23
  spec/loggability_spec.rb
data/README.rdoc CHANGED
@@ -206,6 +206,36 @@ methods on Loggability::Logger:
206
206
  Loggability.output_to( "/tmp/my_project_log.html" )
207
207
 
208
208
 
209
+ === Temporarily Overriding Logging Behavior
210
+
211
+ Sometimes you want to log one particular chunk of code at a different
212
+ level, or to a different destination, and then restore everything back
213
+ to the way it was afterwards.
214
+
215
+ Loggability has a few ways of doing that:
216
+
217
+ # Log only fatal errors...
218
+ Loggability.with_level( :fatal ) do
219
+ ...
220
+ end
221
+
222
+ # Log everything to an array for the block
223
+ logs = []
224
+ Loggability.outputting_to( logs ) do
225
+ ...
226
+ end
227
+
228
+ # Log using the HTML formatter
229
+ Loggability.formatted_with( :html ) do
230
+ ...
231
+ end
232
+
233
+ # Or chain them together:
234
+ Loggability.with_level( :debug ).outputting_to( $stderr ).formatted_with( :color ) do
235
+ Client.connect!
236
+ end
237
+
238
+
209
239
  == Contributing
210
240
 
211
241
  You can check out the current development source with
data/Rakefile CHANGED
@@ -11,6 +11,7 @@ end
11
11
  Hoe.plugin :mercurial
12
12
  Hoe.plugin :signing
13
13
  Hoe.plugin :deveiate
14
+ Hoe.plugin :bundler
14
15
 
15
16
  Hoe.plugins.delete :rubyforge
16
17
 
@@ -22,11 +23,12 @@ hoespec = Hoe.spec 'loggability' do
22
23
  self.developer 'Michael Granger', 'ged@FaerieMUD.org'
23
24
 
24
25
  self.dependency 'hoe-deveiate', '~> 0.3', :developer
26
+ self.dependency 'hoe-bundler', '~> 1.2', :developer
25
27
  self.dependency 'simplecov', '~> 0.7', :developer
26
28
  self.dependency 'configurability', '~> 2.0', :developer
27
29
 
28
- self.spec_extras[:licenses] = ["Ruby"]
29
- self.require_ruby_version( '>=1.8.7' )
30
+ self.license "Ruby"
31
+ self.require_ruby_version( '>=1.9.3' )
30
32
  self.hg_sign_tags = true if self.respond_to?( :hg_sign_tags= )
31
33
  self.check_history_on_release = true if self.respond_to?( :check_history_on_release= )
32
34
 
@@ -36,7 +38,7 @@ end
36
38
  ENV['VERSION'] ||= hoespec.spec.version.to_s
37
39
 
38
40
  # Ensure the specs pass before checking in
39
- task 'hg:precheckin' => [ :check_history, :check_manifest, :spec ]
41
+ task 'hg:precheckin' => [ :check_history, 'bundler:gemfile', :check_manifest, :spec ]
40
42
 
41
43
 
42
44
  desc "Build a coverage report"
@@ -0,0 +1,48 @@
1
+ # -*- ruby -*-
2
+ #encoding: utf-8
3
+
4
+ require 'loggability' unless defined?( Loggability )
5
+
6
+ # Methods to install for objects which call +log_to+.
7
+ module Loggability::LogClient
8
+
9
+ ##
10
+ # The key of the log host this client targets
11
+ attr_accessor :log_host_key
12
+
13
+ ### Return the Loggability::Logger object associated with the log host the
14
+ ### client is logging to.
15
+ ### :TODO: Use delegation for efficiency.
16
+ def log
17
+ @__log ||= Loggability[ self ].proxy_for( self )
18
+ end
19
+
20
+
21
+ ### Inheritance hook -- set the log host key of subclasses to the same
22
+ ### thing as the extended class.
23
+ def inherited( subclass )
24
+ super
25
+ Loggability.log.debug "Setting up subclass %p of %p to log to %p" %
26
+ [ subclass, self, self.log_host_key ]
27
+ subclass.log_host_key = self.log_host_key
28
+ end
29
+
30
+
31
+ # Stuff that gets added to instances of Classes that are log hosts.
32
+ module InstanceMethods
33
+
34
+ ### Fetch the key of the log host the instance of this client targets
35
+ def log_host_key
36
+ return self.class.log_host_key
37
+ end
38
+
39
+
40
+ ### Delegate to the class's logger.
41
+ def log
42
+ @__log ||= Loggability[ self.class ].proxy_for( self )
43
+ end
44
+
45
+ end # module InstanceMethods
46
+
47
+ end # module Loggability::LogClient
48
+
@@ -163,7 +163,7 @@ class Loggability::Logger < ::Logger
163
163
  dev = if self.logdev.respond_to?( :dev )
164
164
  self.logdev.dev.class
165
165
  else
166
- self.logdev.target.class
166
+ self.logdev
167
167
  end
168
168
 
169
169
  return "#<%p:%#x severity: %s, formatter: %s, outputting to: %p>" % [
@@ -185,6 +185,25 @@ class Loggability::Logger < ::Logger
185
185
  end
186
186
 
187
187
 
188
+ ### Return a Hash that contains its settings suitable for restoration via
189
+ ### #restore_settings later.
190
+ def settings
191
+ return {
192
+ level: self.level,
193
+ logdev: self.logdev,
194
+ formatter: self.formatter,
195
+ }
196
+ end
197
+
198
+
199
+ ### Restore the level, logdev, and formatter from the given +settings+.
200
+ def restore_settings( settings )
201
+ self.level = settings[:level] if settings[ :level ]
202
+ self.output_to( settings[:logdev] ) if settings[ :logdev ]
203
+ self.format_with( settings[:formatter] ) if settings[ :formatter ]
204
+ end
205
+
206
+
188
207
  #
189
208
  # :section: Severity Level
190
209
  #
@@ -196,8 +215,8 @@ class Loggability::Logger < ::Logger
196
215
  end
197
216
 
198
217
 
199
- ### Set the logger level to +newlevel+, which can be a numeric level (e.g., Logger::DEBUG, etc.),
200
- ### or a symbolic level (e.g., :debug, :info, etc.)
218
+ ### Set the logger level to +newlevel+, which can be a numeric level (e.g.,
219
+ ### Logger::DEBUG, etc.), or a symbolic level (e.g., :debug, :info, etc.)
201
220
  def level=( newlevel )
202
221
  newlevel = LOG_LEVELS[ newlevel.to_sym ] if
203
222
  newlevel.respond_to?( :to_sym ) && LOG_LEVELS.key?( newlevel.to_sym )
@@ -218,7 +237,10 @@ class Loggability::Logger < ::Logger
218
237
  ### logging to IO objects and files (given a filename in a String), this method can also
219
238
  ### set up logging to any object that responds to #<<.
220
239
  def output_to( target, *args )
221
- if target.respond_to?( :write ) || target.is_a?( String )
240
+ if target.is_a?( Logger::LogDevice ) ||
241
+ target.is_a?( Loggability::Logger::AppendingLogDevice )
242
+ self.logdev = target
243
+ elsif target.respond_to?( :write ) || target.is_a?( String )
222
244
  opts = { :shift_age => args.shift || 0, :shift_size => args.shift || 1048576 }
223
245
  self.logdev = Logger::LogDevice.new( target, opts )
224
246
  elsif target.respond_to?( :<< )
@@ -0,0 +1,40 @@
1
+ # -*- ruby -*-
2
+ #encoding: utf-8
3
+
4
+ require 'loggability' unless defined?( Loggability )
5
+
6
+ # Extension for 'log hosts'. A <b>log host</b> is an object that hosts a Loggability::Logger
7
+ # object, and is typically the top of some kind of hierarchy, like a namespace
8
+ # module for a project:
9
+ #
10
+ # module MyProject
11
+ #
12
+ # end
13
+ #
14
+ # This module isn't mean to be used directly -- it's installed via the Loggability#log_as
15
+ # declaration, which also does some other initialization that you'll likely want.
16
+ #
17
+ #
18
+ module Loggability::LogHost
19
+
20
+ # The logger that will be used when the logging subsystem is reset
21
+ attr_accessor :default_logger
22
+
23
+ # The logger that's currently in effect
24
+ attr_reader :logger
25
+ alias_method :log, :logger
26
+
27
+ # The key associated with the logger for this host
28
+ attr_accessor :log_host_key
29
+
30
+
31
+ ### Set the logger associated with the LogHost to +newlogger+. If +newlogger+ isn't a
32
+ ### Loggability::Logger, it will be converted to one.
33
+ def logger=( newlogger )
34
+ @logger = Loggability::Logger( newlogger )
35
+ end
36
+ alias_method :log=, :logger=
37
+
38
+ end # module Loggability::LogHost
39
+
40
+
@@ -0,0 +1,171 @@
1
+ # -*- ruby -*-
2
+ #encoding: utf-8
3
+
4
+ require 'monitor'
5
+ require 'loggability' unless defined?( Loggability )
6
+
7
+
8
+ # A class which encapsulates the logic and data of temporarily overriding one or
9
+ # more aspects of logging for the execution of one or more blocks of code.
10
+ #
11
+ # It's not meant to be used directly, but via one of the override aggregate methods
12
+ # on Loggability:
13
+ #
14
+ # * Loggability.with_level
15
+ # * Loggability.outputting_to
16
+ # * Loggability.formatted_with
17
+ #
18
+ class Loggability::Override
19
+ include MonitorMixin
20
+
21
+
22
+ ### Return an Override with its logging level set to +newlevel+.
23
+ def self::with_level( new_level )
24
+ return self.new( level: new_level )
25
+ end
26
+
27
+
28
+ ### Return an Override with its logging output set to +new_destination+.
29
+ def self::outputting_to( new_destination )
30
+ return self.new( logdev: new_destination )
31
+ end
32
+
33
+
34
+ ### Return an Override with its logging formatter set to +formatter+.
35
+ def self::formatted_with( new_formatter )
36
+ return self.new( formatter: new_formatter )
37
+ end
38
+
39
+
40
+ ### Create a new Override with the specified +settings+ that will be applied
41
+ ### during a call to #call, and then reverted when #call returns. Valid +settings+
42
+ ### are:
43
+ ###
44
+ ### [:level]
45
+ ### Set the level of all Loggers to the value.
46
+ ### [:logdev]
47
+ ### Set the destination log device of all Loggers to the value.
48
+ ### [:formatter]
49
+ ### Set the formatter for all Loggers to the value (a Loggability::Formatter).
50
+ ###
51
+ def initialize( settings={} )
52
+ super()
53
+
54
+ @settings = settings
55
+ @overridden_settings = {}
56
+ end
57
+
58
+
59
+ ### Copy constructor -- make copies of the internal data structures
60
+ ### when duplicated.
61
+ def initialize_copy( original )
62
+ @settings = original.settings.dup
63
+ @overridden_settings = {}
64
+ end
65
+
66
+
67
+ ######
68
+ public
69
+ ######
70
+
71
+ # The Override's settings Hash (the settings that will be applied during
72
+ # an overridden #call).
73
+ attr_reader :settings
74
+
75
+ # The original settings preserved by the Override during a call to #call,
76
+ # keyed by the logger they belong to.
77
+ attr_reader :overridden_settings
78
+
79
+
80
+ ### Call the provided block with configured overrides applied, and then restore
81
+ ### the previous settings before control is returned.
82
+ def call
83
+ self.apply_overrides
84
+ yield
85
+ ensure
86
+ self.restore_overridden_settings
87
+ end
88
+
89
+
90
+ #
91
+ # Mutator Methods
92
+ #
93
+
94
+ ### Return a clone of the receiving Override with its logging level
95
+ ### set to +newlevel+.
96
+ def with_level( new_level )
97
+ return self.clone_with( level: new_level )
98
+ end
99
+
100
+
101
+ ### Return a clone of the receiving Override with its logging output
102
+ ### set to +new_destination+.
103
+ def outputting_to( new_destination )
104
+ return self.clone_with( logdev: new_destination )
105
+ end
106
+
107
+
108
+ ### Return a clone of the receiving Override with its logging formatter
109
+ ### set to +formatter+.
110
+ def formatted_with( new_formatter )
111
+ return self.clone_with( formatter: new_formatter )
112
+ end
113
+
114
+
115
+ ### Return the object as a human-readable string suitable for debugging.
116
+ def inspect
117
+ return "#<%p:%#016x formatter: %s, level: %s, output: %s>" % [
118
+ self.class,
119
+ self.object_id * 2,
120
+ self.settings[:formatter] || '-',
121
+ self.settings[:level] || '-',
122
+ self.settings[:logdev] ? self.settings[:logdev].class : '-',
123
+ ]
124
+ end
125
+
126
+
127
+ #########
128
+ protected
129
+ #########
130
+
131
+ ### Return a clone that has been modified with the specified +new_settings+.
132
+ def clone_with( new_settings )
133
+ newobj = self.dup
134
+ newobj.settings.merge!( new_settings )
135
+
136
+ return newobj
137
+ end
138
+
139
+
140
+ ### Apply any configured overrides to all loggers.
141
+ def apply_overrides
142
+ self.synchronize do
143
+ raise LocalJumpError, "can't be called re-entrantly" unless
144
+ @overridden_settings.empty?
145
+ @overridden_settings = self.gather_current_settings
146
+ end
147
+
148
+ Loggability.log_hosts.each do |key, host|
149
+ host.logger.restore_settings( self.settings )
150
+ end
151
+ end
152
+
153
+
154
+ ### Return a Hash of Loggers with the settings they currently have.
155
+ def gather_current_settings
156
+ return Loggability.log_hosts.values.each_with_object( {} ) do |host, hash|
157
+ hash[ host ] = host.logger.settings
158
+ end
159
+ end
160
+
161
+
162
+ ### Restore the last settings saved by #apply_overrides to their corresponding
163
+ ### loggers.
164
+ def restore_overridden_settings
165
+ @overridden_settings.each do |host, settings|
166
+ host.logger.restore_settings( settings )
167
+ end
168
+ @overridden_settings.clear
169
+ end
170
+
171
+ end # class Loggability::Override
data/lib/loggability.rb CHANGED
@@ -9,10 +9,10 @@ require 'date'
9
9
  module Loggability
10
10
 
11
11
  # Package version constant
12
- VERSION = '0.7.0'
12
+ VERSION = '0.8.0'
13
13
 
14
14
  # VCS revision
15
- REVISION = %q$Revision: 7e7b1c51eb3e $
15
+ REVISION = %q$Revision: 44b025b728e6 $
16
16
 
17
17
  # The key for the global logger (Loggability's own logger)
18
18
  GLOBAL_KEY = :__global__
@@ -53,6 +53,12 @@ module Loggability
53
53
  @log_hosts = {}
54
54
 
55
55
 
56
+ # Automatically log the log host and log client mixins when they're referenced
57
+ autoload :LogHost, 'loggability/loghost'
58
+ autoload :LogClient, 'loggability/logclient'
59
+ autoload :Override, 'loggability/override'
60
+
61
+
56
62
  ### Return the library's version string
57
63
  def self::version_string( include_buildnum=false )
58
64
  vstring = "%s %s" % [ self.name, VERSION ]
@@ -145,6 +151,21 @@ module Loggability
145
151
  end
146
152
 
147
153
 
154
+ ### Aggregate method: set the log level on all loggers to +level+ for the duration
155
+ ### of the +block+, restoring the original levels afterward. If no block is given, returns a
156
+ ### Loggability::Override object that set the log level to +level+ while its +#call+
157
+ ### method is being called.
158
+ def self::with_level( level, &block )
159
+ override = Loggability::Override.with_level( level )
160
+
161
+ if block
162
+ return override.call( &block )
163
+ else
164
+ return override
165
+ end
166
+ end
167
+
168
+
148
169
  ##
149
170
  # :method: output_to
150
171
  # :call-seq:
@@ -161,6 +182,21 @@ module Loggability
161
182
  end
162
183
 
163
184
 
185
+ ### Aggregate method: set all loggers to log to +destination+ for the duration of the
186
+ ### +block+, restoring the original destination afterward. If no block is given, returns a
187
+ ### Loggability::Override object that will log to +destination+ whenever its +#call+ method is
188
+ ### called.
189
+ def self::outputting_to( newdevice, &block )
190
+ override = Loggability::Override.outputting_to( newdevice )
191
+
192
+ if block
193
+ return override.call( &block )
194
+ else
195
+ return override
196
+ end
197
+ end
198
+
199
+
164
200
  ##
165
201
  # :method: format_with
166
202
  # :call-seq:
@@ -179,83 +215,19 @@ module Loggability
179
215
  end
180
216
 
181
217
 
182
- # Extension for 'log hosts'. A <b>log host</b> is an object that hosts a Loggability::Logger
183
- # object, and is typically the top of some kind of hierarchy, like a namespace
184
- # module for a project:
185
- #
186
- # module MyProject
187
- #
188
- # end
189
- #
190
- # This module isn't mean to be used directly -- it's installed via the Loggability#log_as
191
- # declaration, which also does some other initialization that you'll likely want.
192
- #
193
- #
194
- module LogHost
195
-
196
- # The logger that will be used when the logging subsystem is reset
197
- attr_accessor :default_logger
198
-
199
- # The logger that's currently in effect
200
- attr_reader :logger
201
- alias_method :log, :logger
202
-
203
- # The key associated with the logger for this host
204
- attr_accessor :log_host_key
218
+ ### Aggregate method: set all loggers to log with the given +formatter+ for the duration
219
+ ### of the +block+, restoring the original formatters afterward. If no block is given,
220
+ ### returns a Loggability::Override object that will override all formatters whenever its
221
+ ### +#call+ method is called.
222
+ def self::formatted_with( formatter, &block )
223
+ override = Loggability::Override.formatted_with( formatter )
205
224
 
206
-
207
- ### Set the logger associated with the LogHost to +newlogger+. If +newlogger+ isn't a
208
- ### Loggability::Logger, it will be converted to one.
209
- def logger=( newlogger )
210
- @logger = Loggability::Logger( newlogger )
211
- end
212
- alias_method :log=, :logger=
213
-
214
- end # module LogHost
215
-
216
-
217
- # Methods to install for objects which call +log_to+.
218
- module LogClient
219
-
220
- ##
221
- # The key of the log host this client targets
222
- attr_accessor :log_host_key
223
-
224
- ### Return the Loggability::Logger object associated with the log host the
225
- ### client is logging to.
226
- ### :TODO: Use delegation for efficiency.
227
- def log
228
- @__log ||= Loggability[ self ].proxy_for( self )
229
- end
230
-
231
-
232
- ### Inheritance hook -- set the log host key of subclasses to the same
233
- ### thing as the extended class.
234
- def inherited( subclass )
235
- super
236
- Loggability.log.debug "Setting up subclass %p of %p to log to %p" %
237
- [ subclass, self, self.log_host_key ]
238
- subclass.log_host_key = self.log_host_key
225
+ if block
226
+ return override.call( &block )
227
+ else
228
+ return override
239
229
  end
240
-
241
-
242
- # Stuff that gets added to instances of Classes that are log hosts.
243
- module InstanceMethods
244
-
245
- ### Fetch the key of the log host the instance of this client targets
246
- def log_host_key
247
- return self.class.log_host_key
248
- end
249
-
250
-
251
- ### Delegate to the class's logger.
252
- def log
253
- @__log ||= Loggability[ self.class ].proxy_for( self )
254
- end
255
-
256
- end # module InstanceMethods
257
-
258
- end # module LogClient
230
+ end
259
231
 
260
232
 
261
233
  #
data/spec/helpers.rb ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+ # vim: set nosta noet ts=4 sw=4:
3
+ # encoding: utf-8
4
+
5
+ BEGIN {
6
+ require 'pathname'
7
+ basedir = Pathname.new( __FILE__ ).dirname.parent
8
+
9
+ libdir = basedir + "lib"
10
+
11
+ $LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
12
+ }
13
+
14
+ # SimpleCov test coverage reporting; enable this using the :coverage rake task
15
+ if ENV['COVERAGE']
16
+ $stderr.puts "\n\n>>> Enabling coverage report.\n\n"
17
+ require 'simplecov'
18
+ SimpleCov.start do
19
+ add_filter 'spec'
20
+ end
21
+ end
22
+
23
+ begin
24
+ require 'configurability'
25
+ rescue LoadError
26
+ end
27
+
28
+ require 'loggability'
29
+ require 'loggability/spechelpers'
30
+
31
+
32
+ # Helpers specific to Loggability specs
33
+ module SpecHelpers
34
+
35
+ ### An object identity matcher for collections.
36
+ class AllBeMatcher
37
+
38
+ def initialize( expected )
39
+ @expected = expected
40
+ end
41
+
42
+ def matches?( collection )
43
+ @collection = collection
44
+ return collection.all? {|obj| obj.equal?(@expected) }
45
+ end
46
+
47
+ def description
48
+ "to all be %p" % [ @expected ]
49
+ end
50
+
51
+ def failure_message
52
+ "but they were: %p" % [ @collection ]
53
+ end
54
+
55
+ end # class AllBeMatcher
56
+
57
+
58
+ ### An object kind matcher for collections
59
+ class AllBeAMatcher
60
+
61
+ def initialize( expected_class )
62
+ @expected_class = expected_class
63
+ end
64
+
65
+ def matches?( collection )
66
+ @collection = collection
67
+ return collection.all? {|obj| obj.is_a?(@expected_class) }
68
+ end
69
+
70
+ def description
71
+ "to all be a %p" % [ @expected_class ]
72
+ end
73
+
74
+ def failure_message
75
+ unmatched = @collection.find {|obj| !obj.is_a?(@expected_class) }
76
+ "but (at least) one was not. It was a %p (%s)" % [
77
+ unmatched.class,
78
+ unmatched.class.ancestors.map(&:inspect).join(' < '),
79
+ ]
80
+ end
81
+
82
+ end # class AllBeAMatcher
83
+
84
+
85
+ ###############
86
+ module_function
87
+ ###############
88
+
89
+ ### Return true if the actual value includes the specified +objects+.
90
+ def all_be( expected_object )
91
+ AllBeMatcher.new( expected_object )
92
+ end
93
+
94
+ ### Returns +true+ if every object in the collection inherits from the +expected_class+.
95
+ def all_be_a( expected_class )
96
+ AllBeAMatcher.new( expected_class )
97
+ end
98
+
99
+ end # module SpecHelpers
100
+
101
+
102
+ ### Mock with RSpec
103
+ RSpec.configure do |c|
104
+ c.treat_symbols_as_metadata_keys_with_true_values = true
105
+ c.run_all_when_everything_filtered = true
106
+ c.filter_run :focus
107
+ c.order = 'random'
108
+ c.mock_with( :rspec ) do |mock|
109
+ mock.syntax = :expect
110
+ end
111
+
112
+ c.include( SpecHelpers )
113
+ c.include( Loggability::SpecHelpers )
114
+ c.filter_run_excluding( :configurability ) unless defined?( Configurability )
115
+ end
116
+