twiglet 2.3.7 → 2.4.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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +14 -0
- data/.github/workflows/version-forget-me-not.yml +16 -0
- data/.gitignore +1 -0
- data/Dockerfile +7 -0
- data/Gemfile +1 -0
- data/Makefile +21 -0
- data/README.md +18 -6
- data/Rakefile +1 -1
- data/lib/twiglet/formatter.rb +2 -27
- data/lib/twiglet/logger.rb +4 -2
- data/lib/twiglet/message.rb +24 -0
- data/lib/twiglet/version.rb +1 -1
- data/test/logger_test.rb +57 -40
- data/test/message_test.rb +31 -0
- data/test/test_coverage.rb +13 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a9eac4966bd34b02389637e38100f843f842fc115bad74d9480dc5b87a1dcad2
|
4
|
+
data.tar.gz: 3fb45d8d76a99246f4a215e42fa15dfa52b3f8f7cd8821edf8590653a114514c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 276587b79e63ad48de407c26ad113e64c6fb2819c991622f3f6ea50abe583853991a7f32ceafa4fc2008dff2a4ff4216766c53d0910ff8538ad26430474573f5
|
7
|
+
data.tar.gz: a963f5d218c7c8c327400245b122f83873201191c01828efa125418ea6e0b08d21c86a53ab791aedc9fb900a8642cb0e1130a835516388e922da6b00ccf83880
|
data/.github/workflows/ruby.yml
CHANGED
@@ -4,6 +4,9 @@ on:
|
|
4
4
|
push:
|
5
5
|
branches:
|
6
6
|
|
7
|
+
env:
|
8
|
+
CI: true
|
9
|
+
|
7
10
|
jobs:
|
8
11
|
build:
|
9
12
|
runs-on: ubuntu-latest
|
@@ -23,11 +26,22 @@ jobs:
|
|
23
26
|
ruby-version: ${{ matrix.ruby-version }}
|
24
27
|
- name: Install dependencies
|
25
28
|
run: bundle install
|
29
|
+
- name: install cc-test-reporter
|
30
|
+
env:
|
31
|
+
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
|
32
|
+
run: |
|
33
|
+
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-0.6.3-linux-amd64 > ./cc-test-reporter
|
34
|
+
chmod +x ./cc-test-reporter
|
35
|
+
./cc-test-reporter before-build
|
26
36
|
- name: Rubocop Check
|
27
37
|
run: bundle exec rubocop
|
28
38
|
- name: Run all tests
|
29
39
|
run: bundle exec rake test
|
30
40
|
shell: bash
|
41
|
+
- name: upload test coverage to CodeClimate
|
42
|
+
env:
|
43
|
+
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
|
44
|
+
run: ./cc-test-reporter after-build
|
31
45
|
- name: Run example_app
|
32
46
|
run: bundle exec ruby example_app.rb
|
33
47
|
shell: bash
|
@@ -0,0 +1,16 @@
|
|
1
|
+
name: Check version
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
types: [opened, synchronize]
|
8
|
+
jobs:
|
9
|
+
build:
|
10
|
+
runs-on: ubuntu-18.04
|
11
|
+
|
12
|
+
steps:
|
13
|
+
- uses: simplybusiness/version-forget-me-not@v1
|
14
|
+
env:
|
15
|
+
ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
16
|
+
VERSION_FILE_PATH: "lib/twiglet/version.rb"
|
data/.gitignore
CHANGED
data/Dockerfile
ADDED
data/Gemfile
CHANGED
data/Makefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
.PHONY: all build clean shell test
|
2
|
+
|
3
|
+
all: clean build test
|
4
|
+
|
5
|
+
build:
|
6
|
+
docker build -t simplybusiness/ruby-dev:2.6.5 .
|
7
|
+
|
8
|
+
clean:
|
9
|
+
rm -f *~
|
10
|
+
|
11
|
+
shell:
|
12
|
+
docker run -it \
|
13
|
+
-v `pwd`:/var/app \
|
14
|
+
simplybusiness/ruby-dev:2.6.5 \
|
15
|
+
bash
|
16
|
+
|
17
|
+
test:
|
18
|
+
docker run -it \
|
19
|
+
-v `pwd`:/var/app \
|
20
|
+
simplybusiness/ruby-dev:2.6.5 \
|
21
|
+
bundle exec rake test
|
data/README.md
CHANGED
@@ -42,9 +42,10 @@ This will write to STDOUT a JSON string:
|
|
42
42
|
|
43
43
|
Obviously the timestamp will be different.
|
44
44
|
|
45
|
-
Alternatively, if you just want to log some error
|
45
|
+
Alternatively, if you just want to log some error string:
|
46
|
+
|
46
47
|
```ruby
|
47
|
-
logger.error(
|
48
|
+
logger.error("Emergency! There's an Emergency going on")
|
48
49
|
```
|
49
50
|
|
50
51
|
This will write to STDOUT a JSON string:
|
@@ -53,11 +54,22 @@ This will write to STDOUT a JSON string:
|
|
53
54
|
{"service":{"name":"service name"},"@timestamp":"2020-05-14T10:54:59.164+01:00","log":{"level":"error"}, "message":"Emergency! There's an Emergency going on"}
|
54
55
|
```
|
55
56
|
|
56
|
-
|
57
|
+
A message is always required unless a block is provided. The message can be an object or a string.
|
58
|
+
|
59
|
+
An optional error can also be provided, in which case the error message and backtrace will be logged in the relevant ECS compliant fields:
|
57
60
|
|
58
61
|
```ruby
|
59
62
|
db_err = StandardError.new('Connection timed-out')
|
60
63
|
logger.error({ message: 'DB connection failed.' }, db_err)
|
64
|
+
|
65
|
+
# this is also valid
|
66
|
+
logger.error('DB connection failed.', db_err)
|
67
|
+
```
|
68
|
+
|
69
|
+
These will both result in the same JSON string written to STDOUT:
|
70
|
+
|
71
|
+
```json
|
72
|
+
{"ecs":{"version":"1.5.0"},"@timestamp":"2020-08-21T15:44:37.890Z","service":{"name":"service name"},"log":{"level":"error"},"message":"DB connection failed.","error":{"message":"Connection timed-out"}}
|
61
73
|
```
|
62
74
|
|
63
75
|
Add log event specific information simply as attributes in a hash:
|
@@ -81,18 +93,18 @@ This writes:
|
|
81
93
|
{"service":{"name":"service name"},"@timestamp":"2020-05-14T10:56:49.527+01:00","log":{"level":"info"},"event":{"action":"HTTP request"},"message":"GET /pets success","trace":{"id":"1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb"},"http":{"request":{"method":"get"},"response":{"status_code":200}},"url":{"path":"/pets"}}
|
82
94
|
```
|
83
95
|
|
84
|
-
Similar to error you can use
|
96
|
+
Similar to error you can use string logging here as:
|
85
97
|
|
86
98
|
```
|
87
99
|
logger.info('GET /pets success')
|
88
100
|
```
|
101
|
+
|
89
102
|
This writes:
|
90
103
|
|
91
104
|
```json
|
92
105
|
{"service":{"name":"service name"},"@timestamp":"2020-05-14T10:56:49.527+01:00","log":{"level":"info"}}
|
93
106
|
```
|
94
107
|
|
95
|
-
|
96
108
|
It may be that when making a series of logs that write information about a single event, you may want to avoid duplication by creating an event specific logger that includes the context:
|
97
109
|
|
98
110
|
```ruby
|
@@ -117,7 +129,7 @@ which will print:
|
|
117
129
|
{"service":{"name":"service name"},"@timestamp":"2020-05-14T10:58:30.780+01:00","log":{"level":"error"},"event":{"action":"HTTP request"},"trace":{"id":"126bb6fa-28a2-470f-b013-eefbf9182b2d"},"message":"Error 500 in /pets/buy","http":{"request":{"method":"post","url.path":"/pet/buy"},"response":{"status_code":500}}}
|
118
130
|
```
|
119
131
|
|
120
|
-
## Use of dotted keys
|
132
|
+
## Use of dotted keys (DEPRECATED)
|
121
133
|
|
122
134
|
Writing nested json objects could be confusing. This library has a built-in feature to convert dotted keys into nested objects, so if you log like this:
|
123
135
|
|
data/Rakefile
CHANGED
@@ -2,6 +2,6 @@ require 'rake/testtask'
|
|
2
2
|
|
3
3
|
Rake::TestTask.new do |t|
|
4
4
|
t.libs << "test"
|
5
|
-
t.test_files = FileList['test/*_test.rb', 'examples/rack/request_logger_test.rb']
|
5
|
+
t.test_files = FileList['test/test_coverage.rb', 'test/*_test.rb', 'examples/rack/request_logger_test.rb']
|
6
6
|
t.verbose = true
|
7
7
|
end
|
data/lib/twiglet/formatter.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require_relative '../hash_extensions'
|
3
|
+
require_relative 'message'
|
3
4
|
|
4
5
|
module Twiglet
|
5
6
|
class Formatter < ::Logger::Formatter
|
@@ -17,38 +18,12 @@ module Twiglet
|
|
17
18
|
|
18
19
|
def call(severity, _time, _progname, msg)
|
19
20
|
level = severity.downcase
|
20
|
-
log(level: level, message: msg)
|
21
|
+
log(level: level, message: Message.new(msg))
|
21
22
|
end
|
22
23
|
|
23
24
|
private
|
24
25
|
|
25
26
|
def log(level:, message:)
|
26
|
-
case message
|
27
|
-
when String
|
28
|
-
log_text(level, message: message)
|
29
|
-
when Hash
|
30
|
-
log_object(level, message: message)
|
31
|
-
else
|
32
|
-
raise('Message must be String or Hash')
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def log_text(level, message:)
|
37
|
-
raise('The \'message\' property of log object must not be empty') if message.strip.empty?
|
38
|
-
|
39
|
-
message = { message: message }
|
40
|
-
log_message(level, message: message)
|
41
|
-
end
|
42
|
-
|
43
|
-
def log_object(level, message:)
|
44
|
-
message = message.transform_keys(&:to_sym)
|
45
|
-
message.key?(:message) || raise('Log object must have a \'message\' property')
|
46
|
-
message[:message].strip.empty? && raise('The \'message\' property of log object must not be empty')
|
47
|
-
|
48
|
-
log_message(level, message: message)
|
49
|
-
end
|
50
|
-
|
51
|
-
def log_message(level, message:)
|
52
27
|
base_message = {
|
53
28
|
ecs: {
|
54
29
|
version: '1.5.0'
|
data/lib/twiglet/logger.rb
CHANGED
@@ -5,6 +5,7 @@ require 'time'
|
|
5
5
|
require 'json'
|
6
6
|
require_relative 'formatter'
|
7
7
|
require_relative '../hash_extensions'
|
8
|
+
require_relative 'message'
|
8
9
|
|
9
10
|
module Twiglet
|
10
11
|
class Logger < ::Logger
|
@@ -29,15 +30,16 @@ module Twiglet
|
|
29
30
|
super(output, formatter: formatter, level: level)
|
30
31
|
end
|
31
32
|
|
32
|
-
def error(message =
|
33
|
+
def error(message = nil, error = nil, &block)
|
33
34
|
if error
|
34
35
|
error_fields = {
|
35
36
|
'error': {
|
37
|
+
'type': error.class,
|
36
38
|
'message': error.message
|
37
39
|
}
|
38
40
|
}
|
39
41
|
add_stack_trace(error_fields, error)
|
40
|
-
message
|
42
|
+
message = Message.new(message).merge(error_fields)
|
41
43
|
end
|
42
44
|
|
43
45
|
super(message, &block)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Twiglet
|
2
|
+
class Message < Hash
|
3
|
+
def initialize(msg)
|
4
|
+
case msg
|
5
|
+
when String
|
6
|
+
self[:message] = msg
|
7
|
+
when Hash
|
8
|
+
replace(msg.transform_keys!(&:to_sym))
|
9
|
+
end
|
10
|
+
|
11
|
+
validate!
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def validate!
|
17
|
+
raise 'Message must be initialized with a String or a non-empty Hash' if empty?
|
18
|
+
|
19
|
+
raise 'Log object must have a \'message\' property' unless self[:message]
|
20
|
+
|
21
|
+
raise 'The \'message\' property of the log object must not be empty' if self[:message].strip.empty?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/twiglet/version.rb
CHANGED
data/test/logger_test.rb
CHANGED
@@ -149,39 +149,6 @@ describe Twiglet::Logger do
|
|
149
149
|
assert_equal expected_output, @buffer.string
|
150
150
|
end
|
151
151
|
|
152
|
-
it 'should be able to convert dotted keys to nested objects' do
|
153
|
-
@logger.debug({
|
154
|
-
"trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
|
155
|
-
message: 'customer bought a dog',
|
156
|
-
"pet.name": 'Barker',
|
157
|
-
"pet.species": 'dog',
|
158
|
-
"pet.breed": 'Bitsa'
|
159
|
-
})
|
160
|
-
log = read_json(@buffer)
|
161
|
-
|
162
|
-
assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
|
163
|
-
assert_equal 'customer bought a dog', log[:message]
|
164
|
-
assert_equal 'Barker', log[:pet][:name]
|
165
|
-
assert_equal 'dog', log[:pet][:species]
|
166
|
-
assert_equal 'Bitsa', log[:pet][:breed]
|
167
|
-
end
|
168
|
-
|
169
|
-
it 'should be able to mix dotted keys and nested objects' do
|
170
|
-
@logger.debug({
|
171
|
-
"trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
|
172
|
-
message: 'customer bought a dog',
|
173
|
-
pet: {name: 'Barker', breed: 'Bitsa'},
|
174
|
-
"pet.species": 'dog'
|
175
|
-
})
|
176
|
-
log = read_json(@buffer)
|
177
|
-
|
178
|
-
assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
|
179
|
-
assert_equal 'customer bought a dog', log[:message]
|
180
|
-
assert_equal 'Barker', log[:pet][:name]
|
181
|
-
assert_equal 'dog', log[:pet][:species]
|
182
|
-
assert_equal 'Bitsa', log[:pet][:breed]
|
183
|
-
end
|
184
|
-
|
185
152
|
it 'should work with mixed string and symbol properties' do
|
186
153
|
log = {
|
187
154
|
"trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb'
|
@@ -205,6 +172,18 @@ describe Twiglet::Logger do
|
|
205
172
|
assert_equal 'Bitsa', actual_log[:pet][:breed]
|
206
173
|
end
|
207
174
|
|
175
|
+
LEVELS.each do |attrs|
|
176
|
+
it "should correctly log level when calling #{attrs[:method]}" do
|
177
|
+
@logger.public_send(attrs[:method], {message: 'a log message'})
|
178
|
+
actual_log = read_json(@buffer)
|
179
|
+
|
180
|
+
assert_equal attrs[:level], actual_log[:log][:level]
|
181
|
+
assert_equal 'a log message', actual_log[:message]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe 'logging an exception' do
|
208
187
|
it 'should log an error with backtrace' do
|
209
188
|
begin
|
210
189
|
1 / 0
|
@@ -216,6 +195,7 @@ describe Twiglet::Logger do
|
|
216
195
|
|
217
196
|
assert_equal 'Artificially raised exception', actual_log[:message]
|
218
197
|
assert_equal 'divided by 0', actual_log[:error][:message]
|
198
|
+
assert_equal 'ZeroDivisionError', actual_log[:error][:type]
|
219
199
|
assert_match 'logger_test.rb', actual_log[:error][:stack_trace].lines.first
|
220
200
|
end
|
221
201
|
|
@@ -226,18 +206,20 @@ describe Twiglet::Logger do
|
|
226
206
|
actual_log = read_json(@buffer)
|
227
207
|
|
228
208
|
assert_equal 'Artificially raised exception', actual_log[:message]
|
209
|
+
assert_equal 'StandardError', actual_log[:error][:type]
|
229
210
|
assert_equal 'Connection timed-out', actual_log[:error][:message]
|
230
211
|
refute actual_log[:error].key?(:stack_trace)
|
231
212
|
end
|
232
213
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
actual_log = read_json(@buffer)
|
214
|
+
it 'should log an error with string message' do
|
215
|
+
e = StandardError.new('Unknown error')
|
216
|
+
@logger.error('Artificially raised exception with string message', e)
|
237
217
|
|
238
|
-
|
239
|
-
|
240
|
-
|
218
|
+
actual_log = read_json(@buffer)
|
219
|
+
|
220
|
+
assert_equal 'Artificially raised exception with string message', actual_log[:message]
|
221
|
+
assert_equal 'StandardError', actual_log[:error][:type]
|
222
|
+
assert_equal 'Unknown error', actual_log[:error][:message]
|
241
223
|
end
|
242
224
|
end
|
243
225
|
|
@@ -300,6 +282,41 @@ describe Twiglet::Logger do
|
|
300
282
|
end
|
301
283
|
end
|
302
284
|
|
285
|
+
describe 'dotted keys' do
|
286
|
+
it 'should be able to convert dotted keys to nested objects' do
|
287
|
+
@logger.debug({
|
288
|
+
"trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
|
289
|
+
message: 'customer bought a dog',
|
290
|
+
"pet.name": 'Barker',
|
291
|
+
"pet.species": 'dog',
|
292
|
+
"pet.breed": 'Bitsa'
|
293
|
+
})
|
294
|
+
log = read_json(@buffer)
|
295
|
+
|
296
|
+
assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
|
297
|
+
assert_equal 'customer bought a dog', log[:message]
|
298
|
+
assert_equal 'Barker', log[:pet][:name]
|
299
|
+
assert_equal 'dog', log[:pet][:species]
|
300
|
+
assert_equal 'Bitsa', log[:pet][:breed]
|
301
|
+
end
|
302
|
+
|
303
|
+
it 'should be able to mix dotted keys and nested objects' do
|
304
|
+
@logger.debug({
|
305
|
+
"trace.id": '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb',
|
306
|
+
message: 'customer bought a dog',
|
307
|
+
pet: {name: 'Barker', breed: 'Bitsa'},
|
308
|
+
"pet.species": 'dog'
|
309
|
+
})
|
310
|
+
log = read_json(@buffer)
|
311
|
+
|
312
|
+
assert_equal '1c8a5fb2-fecd-44d8-92a4-449eb2ce4dcb', log[:trace][:id]
|
313
|
+
assert_equal 'customer bought a dog', log[:message]
|
314
|
+
assert_equal 'Barker', log[:pet][:name]
|
315
|
+
assert_equal 'dog', log[:pet][:species]
|
316
|
+
assert_equal 'Bitsa', log[:pet][:breed]
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
303
320
|
describe 'logger level' do
|
304
321
|
[
|
305
322
|
{ expression: :info, level: 1 },
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative '../lib/twiglet/message'
|
3
|
+
|
4
|
+
describe Twiglet::Message do
|
5
|
+
it 'raises if message is empty' do
|
6
|
+
assert_raises RuntimeError do
|
7
|
+
Twiglet::Message.new(' ')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'raises if message is not provided' do
|
12
|
+
assert_raises RuntimeError do
|
13
|
+
Twiglet::Message.new(foo: 'bar')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'raises on unrecognized inputs' do
|
18
|
+
assert_raises RuntimeError do
|
19
|
+
Twiglet::Message.new(OpenStruct.new(message: 'hello'))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns a message hash from a string' do
|
24
|
+
assert_equal Twiglet::Message.new('hello, world'), { message: 'hello, world' }
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns a message hash with symbolized keys' do
|
28
|
+
input_message = { 'key' => 'value', 'message' => 'hello, world' }
|
29
|
+
assert_equal Twiglet::Message.new(input_message), { key: 'value', message: 'hello, world' }
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
SimpleCov.start do
|
4
|
+
add_filter "/test/"
|
5
|
+
add_filter "examples/rack/request_logger_test.rb"
|
6
|
+
|
7
|
+
if ENV['CI']
|
8
|
+
formatter SimpleCov::Formatter::SimpleFormatter
|
9
|
+
else
|
10
|
+
formatter SimpleCov::Formatter::MultiFormatter.new([SimpleCov::Formatter::SimpleFormatter,
|
11
|
+
SimpleCov::Formatter::HTMLFormatter])
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twiglet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simply Business
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Like a log, only smaller.
|
14
14
|
email:
|
@@ -20,12 +20,15 @@ files:
|
|
20
20
|
- ".github/CODEOWNERS"
|
21
21
|
- ".github/workflows/gem-publish.yml"
|
22
22
|
- ".github/workflows/ruby.yml"
|
23
|
+
- ".github/workflows/version-forget-me-not.yml"
|
23
24
|
- ".gitignore"
|
24
25
|
- ".rubocop.yml"
|
25
26
|
- ".ruby-version"
|
26
27
|
- CODE_OF_CONDUCT.md
|
28
|
+
- Dockerfile
|
27
29
|
- Gemfile
|
28
30
|
- LICENSE
|
31
|
+
- Makefile
|
29
32
|
- RATIONALE.md
|
30
33
|
- README.md
|
31
34
|
- Rakefile
|
@@ -36,10 +39,13 @@ files:
|
|
36
39
|
- lib/hash_extensions.rb
|
37
40
|
- lib/twiglet/formatter.rb
|
38
41
|
- lib/twiglet/logger.rb
|
42
|
+
- lib/twiglet/message.rb
|
39
43
|
- lib/twiglet/version.rb
|
40
44
|
- test/formatter_test.rb
|
41
45
|
- test/hash_extensions_test.rb
|
42
46
|
- test/logger_test.rb
|
47
|
+
- test/message_test.rb
|
48
|
+
- test/test_coverage.rb
|
43
49
|
- twiglet.gemspec
|
44
50
|
homepage: https://github.com/simplybusiness/twiglet-ruby
|
45
51
|
licenses:
|