hit_counter 0.1.1 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
  4. data/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
  5. data/.github/ISSUE_TEMPLATE/task.md +21 -0
  6. data/.github/PULL_REQUEST_TEMPLATE.md +31 -0
  7. data/.github/dependabot.yml +11 -0
  8. data/.github/workflows/test.yml +42 -0
  9. data/.gitignore +8 -0
  10. data/.simplecov +15 -0
  11. data/CODE_OF_CONDUCT.md +10 -0
  12. data/CONTRIBUTING.md +34 -0
  13. data/Gemfile +12 -12
  14. data/LICENSE.txt +17 -11
  15. data/README.md +120 -0
  16. data/Rakefile +15 -40
  17. data/SECURITY.md +16 -0
  18. data/certs/ivanoblomov.pem +25 -0
  19. data/config/initializers/mime_types.rb +3 -1
  20. data/config/mongoid.yml +6 -0
  21. data/hit_counter.gemspec +20 -87
  22. data/lib/hit_counter.rb +91 -85
  23. data/lib/tasks/install.rake +6 -0
  24. data/lib/version.rb +7 -0
  25. data/public/images/digits/celtic/0.png +0 -0
  26. data/public/images/digits/celtic/1.png +0 -0
  27. data/public/images/digits/celtic/2.png +0 -0
  28. data/public/images/digits/celtic/3.png +0 -0
  29. data/public/images/digits/celtic/4.png +0 -0
  30. data/public/images/digits/celtic/5.png +0 -0
  31. data/public/images/digits/celtic/6.png +0 -0
  32. data/public/images/digits/celtic/7.png +0 -0
  33. data/public/images/digits/celtic/8.png +0 -0
  34. data/public/images/digits/celtic/9.png +0 -0
  35. data/public/images/digits/odometer/0.png +0 -0
  36. data/public/images/digits/odometer/1.png +0 -0
  37. data/public/images/digits/odometer/2.png +0 -0
  38. data/public/images/digits/odometer/3.png +0 -0
  39. data/public/images/digits/odometer/4.png +0 -0
  40. data/public/images/digits/odometer/5.png +0 -0
  41. data/public/images/digits/odometer/6.png +0 -0
  42. data/public/images/digits/odometer/7.png +0 -0
  43. data/public/images/digits/odometer/8.png +0 -0
  44. data/public/images/digits/odometer/9.png +0 -0
  45. data/public/images/digits/scout/0.png +0 -0
  46. data/public/images/digits/scout/1.png +0 -0
  47. data/public/images/digits/scout/2.png +0 -0
  48. data/public/images/digits/scout/3.png +0 -0
  49. data/public/images/digits/scout/4.png +0 -0
  50. data/public/images/digits/scout/5.png +0 -0
  51. data/public/images/digits/scout/6.png +0 -0
  52. data/public/images/digits/scout/7.png +0 -0
  53. data/public/images/digits/scout/8.png +0 -0
  54. data/public/images/digits/scout/9.png +0 -0
  55. data/spec/lib/hit_counter_spec.rb +110 -69
  56. data/spec/spec_helper.rb +52 -3
  57. data.tar.gz.sig +0 -0
  58. metadata +157 -148
  59. metadata.gz.sig +0 -0
  60. data/README.rdoc +0 -82
  61. data/VERSION +0 -1
  62. data/public/images/digits/celtic/0.gif +0 -0
  63. data/public/images/digits/celtic/1.gif +0 -0
  64. data/public/images/digits/celtic/2.gif +0 -0
  65. data/public/images/digits/celtic/3.gif +0 -0
  66. data/public/images/digits/celtic/4.gif +0 -0
  67. data/public/images/digits/celtic/5.gif +0 -0
  68. data/public/images/digits/celtic/6.gif +0 -0
  69. data/public/images/digits/celtic/7.gif +0 -0
  70. data/public/images/digits/celtic/8.gif +0 -0
  71. data/public/images/digits/celtic/9.gif +0 -0
  72. data/public/images/digits/odometer/0.gif +0 -0
  73. data/public/images/digits/odometer/1.gif +0 -0
  74. data/public/images/digits/odometer/2.gif +0 -0
  75. data/public/images/digits/odometer/3.gif +0 -0
  76. data/public/images/digits/odometer/4.gif +0 -0
  77. data/public/images/digits/odometer/5.gif +0 -0
  78. data/public/images/digits/odometer/6.gif +0 -0
  79. data/public/images/digits/odometer/7.gif +0 -0
  80. data/public/images/digits/odometer/8.gif +0 -0
  81. data/public/images/digits/odometer/9.gif +0 -0
  82. data/public/images/digits/scout/0.gif +0 -0
  83. data/public/images/digits/scout/1.gif +0 -0
  84. data/public/images/digits/scout/2.gif +0 -0
  85. data/public/images/digits/scout/3.gif +0 -0
  86. data/public/images/digits/scout/4.gif +0 -0
  87. data/public/images/digits/scout/5.gif +0 -0
  88. data/public/images/digits/scout/6.gif +0 -0
  89. data/public/images/digits/scout/7.gif +0 -0
  90. data/public/images/digits/scout/8.gif +0 -0
  91. data/public/images/digits/scout/9.gif +0 -0
data/lib/hit_counter.rb CHANGED
@@ -1,138 +1,144 @@
1
- # Copyright (c) 2011 Roderick Monje
2
- #
3
- # This program is free software: you can redistribute it and/or modify
4
- # it under the terms of the GNU General Public License as published by
5
- # the Free Software Foundation, either version 3 of the License, or
6
- # (at your option) any later version.
7
- #
8
- # This program is distributed in the hope that it will be useful,
9
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
- # GNU General Public License for more details.
12
- #
13
- # You should have received a copy of the GNU General Public License
14
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
1
+ # Copyright the HitCounter contributors.
2
+ # SPDX-License-Identifier: MIT
3
+ # frozen_string_literal: true
4
+
15
5
  require 'rubygems'
16
6
  require 'bundler/setup'
17
7
  Bundler.require :default
18
8
 
9
+ # Self-hosted Ruby version of that old 90s chestnut, <BLINK>the web-site hit counter</BLINK>
10
+ #
11
+ # @example
12
+ # hc = HitCounter.get 'cnn.com'
13
+ # hc.increment
19
14
  class HitCounter
20
15
  include Mongoid::Document
21
16
  include Mongoid::Timestamps
22
17
 
23
- # Mongo Config ===================================================================================
18
+ # Mongo Config ===============================================================
19
+ field :hits, type: Integer, default: 0
24
20
  field :url
25
- field :hits, :type => Integer, :default => 0
26
21
 
27
22
  # Validates the <code>HitCounter</code>'s URL.
28
23
  #
29
- # If the URI library can parse the value and the scheme is valid, then we assume the url is valid.
24
+ # If the URI library can parse the value and the scheme is valid, then we
25
+ # assume the url is valid.
30
26
  class UrlValidator < ActiveModel::EachValidator
31
- def validate_each record, attribute, value
32
- begin
33
- uri = Addressable::URI.parse value
34
-
35
- if !['http', 'https'].include? uri.scheme
36
- raise Addressable::URI::InvalidURIError
37
- end
38
- rescue Addressable::URI::InvalidURIError
39
- record.errors[attribute] << 'Invalid URL'
40
- end
27
+ private
28
+
29
+ def validate_each(record, attribute, value)
30
+ uri = Addressable::URI.parse value
31
+ raise Addressable::URI::InvalidURIError unless %w[http https].include?(
32
+ uri.scheme
33
+ )
34
+ rescue Addressable::URI::InvalidURIError
35
+ record.errors.add attribute, 'Invalid URL'
41
36
  end
42
37
  end
43
38
 
44
- validates :url, :presence => true, :url => true, :uniqueness => true
39
+ validates :hits, numericality: { only_integer: true }
40
+ validates :url, presence: true, url: true, uniqueness: true
45
41
 
46
- # Class methods ==================================================================================
42
+ # Class methods ==============================================================
47
43
 
48
- # Returns a <code>HitCounter</code> matching the specified URL. The HitCounter is created if no
49
- # matching one is found. In the latter case, the hits argument specifies the starting count.
44
+ # Returns a <code>HitCounter</code> matching the specified URL. The HitCounter
45
+ # is created if no matching one is found. In the latter case, the hits
46
+ # argument specifies the starting count.
50
47
  #
51
- # * *Args*
52
- # - +url+ -> the URL for the site being counted
53
- # - +hits+ -> the number of hits to start with
54
- # * *Returns*
55
- # - the site's HitCounter
56
- def self.get url, hits = 0
57
- args = {:url => HitCounter.normalize_url(url)}
58
- args[:hits] = hits unless HitCounter.exists? :conditions => args
59
- self.find_or_create_by args
48
+ # @param url [String] the URL for the site being counted
49
+ # @param hits [Integer] the number of hits to start with
50
+ # @return [HitCounter] the site's HitCounter
51
+ # @example
52
+ # hc = HitCounter.get 'cnn.com'
53
+ # hc = HitCounter.get 'cnn.com', 100
54
+ def self.get(url, hits = 0)
55
+ args = { url: normalize_url(url) }
56
+ args[:hits] = hits unless where(conditions: args).exists?
57
+ find_or_create_by args
60
58
  end
61
59
 
62
- # Instance methods: Overrides ====================================================================
60
+ # Installs the required Mongoid configuration and image files.
61
+ #
62
+ # @return true
63
+ # @example
64
+ # HitCounter.install
65
+ def self.install
66
+ puts 'Configuring Mongoid and installing image files...'
67
+ full_gem_path = Gem::Specification.find_by_name('hit_counter').full_gem_path
68
+ system "rsync -ruv #{full_gem_path}/config ."
69
+ system "rsync -ruv #{full_gem_path}/public ."
70
+ end
71
+
72
+ # Instance methods: Overrides ================================================
73
+
74
+ # Sets the number of hits.
75
+ #
76
+ # @param value [Integer] the initial number of hits
77
+ # @return [Integer] the number of hits
78
+ # @example
79
+ # hc.hits = 100
80
+ def hits=(value)
81
+ self[:hits] = value.to_i
82
+ end
63
83
 
64
84
  # Sets the URL to be tracked. The http prefix is optional.
65
85
  #
66
- # * *Args*
67
- # - +value+ -> the URL for the site being counted
68
- # * *Returns*
69
- # - the value
70
- def url= value
71
- self[:url] = HitCounter.normalize_url value
86
+ # @param value [String] the URL for the site being counted
87
+ # @return [String] the normalized URL
88
+ # @example
89
+ # hc.url = 'cnn.com'
90
+ def url=(value)
91
+ self[:url] = HitCounter.send(:normalize_url, value)
72
92
  end
73
93
 
74
- # Instance methods ===============================================================================
94
+ # Instance methods ===========================================================
75
95
 
76
96
  # Returns the hit count as a PNG image, using the specified style:
77
97
  # 1 odometer
78
98
  # 2 scout
79
99
  # 3 Celtic
80
100
  #
81
- # * *Args*
82
- # - +style_number+ -> the image style
83
- # * *Returns*
84
- # - the current hit count as a PNG image
85
- def image style_number
86
- image = HitCounter.cat_image self.hits.to_s, HitCounter.normalize_style_number(style_number)
101
+ # @param style_number [String] the image style
102
+ # @return [Magick::Image] the current hit count as a PNG image
103
+ # @example
104
+ # hc.image = 1
105
+ def image(style_number)
106
+ image = HitCounter.send(:cat_image, hits.to_s, HitCounter.send(:normalize_style_number, style_number))
87
107
  image.format = 'png'
88
108
  image
89
109
  end
90
110
 
91
111
  # Increments the hit count and saves the HitCounter.
92
112
  #
93
- # * *Returns*
94
- # - true if the save was successful
113
+ # @return [true] if the save was successful
114
+ # @example
115
+ # hc.increment
95
116
  def increment
96
117
  self.hits += 1
97
- self.save
118
+ save
98
119
  end
99
120
 
100
- private
101
-
102
- STYLES = ['odometer', 'scout', 'celtic']
121
+ # Defines the available image styles as an array. Add yours to the end.
122
+ STYLES = %w[odometer scout celtic].freeze
103
123
 
104
- def self.cat_image number, style_index, images = Magick::ImageList.new
124
+ private_class_method def self.cat_image(number, style_index, images = Magick::ImageList.new)
105
125
  return images.append(false) if number.blank?
106
- HitCounter.cat_image number[1..-1], style_index, images << Magick::Image.read("#{Rails.root}/public/images/digits/#{STYLES[style_index]}/#{number[0..0]}.gif").first
126
+
127
+ cat_image(number[1..-1], style_index, images <<
128
+ Magick::Image.read("#{Rails.root}/public/images/digits/"\
129
+ "#{STYLES[style_index]}/#{number[0..0]}.png").first)
107
130
  end
108
131
 
109
- def self.normalize_style_number value
132
+ private_class_method def self.normalize_style_number(value)
110
133
  value = value.to_i
111
- value -= 1 if value > 0
134
+ value -= 1 if value.positive?
112
135
 
113
- if value >= 0 && value < STYLES.size
114
- return value
115
- else
116
- value % 3
117
- end
136
+ return value if value >= 0 && value < STYLES.size
137
+
138
+ value % 3
118
139
  end
119
140
 
120
- def self.normalize_url value
141
+ private_class_method def self.normalize_url(value)
121
142
  value !~ %r{^http://} ? "http://#{value}" : value
122
143
  end
123
144
  end
124
-
125
- if defined? Rails
126
- class Railtie < Rails::Railtie
127
- rake_tasks do
128
- namespace :hit_counter do
129
- desc 'Install HitCounter into your app.'
130
- task :install do
131
- puts 'Installing required image files...'
132
- system "rsync -ruv #{Gem.searcher.find('hit_counter').full_gem_path}/config ."
133
- system "rsync -ruv #{Gem.searcher.find('hit_counter').full_gem_path}/public ."
134
- end
135
- end
136
- end
137
- end
138
- end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :hit_counter do
4
+ desc 'Install HitCounter into your app.'
5
+ task(:install) { HitCounter.install }
6
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Self-hosted Ruby version of that old 90s chestnut, <BLINK>the web-site hit counter</BLINK>
4
+ class HitCounter
5
+ # This gem's version
6
+ VERSION = '0.1.5' unless defined?(HitCounter::VERSION)
7
+ end
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,109 +1,150 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ # Copyright the HitCounter contributors.
2
+ # SPDX-License-Identifier: MIT
3
+ # frozen_string_literal: true
2
4
 
5
+ require "#{File.dirname(__FILE__)}/../spec_helper"
6
+
7
+ JAVASCRIPT_HACK = %q(eval("console.log('All your base belong to us!')"))
8
+ # rubocop:disable Metrics/BlockLength
3
9
  describe HitCounter do
4
- before :all do
5
- HitCounter.delete_all
6
- @hit_counter = HitCounter.get 'www.google.com'
7
- end
10
+ before(:all) { described_class.delete_all }
11
+
12
+ subject { described_class.get 'www.google.com' }
8
13
 
9
- describe '#get' do
10
- context 'when existing URL' do
11
- describe 'document count' do
12
- specify { HitCounter.count.should == 1 }
14
+ describe '.get' do
15
+ context 'with existing URL' do
16
+ let!(:hit_counter2) { described_class.get subject.url, 10 }
17
+
18
+ describe '.count' do
19
+ it { expect(described_class.count).to eq 1 }
13
20
  end
14
21
 
15
22
  context 'with starting count 10' do
16
- describe 'hits' do
17
- specify { HitCounter.get(@hit_counter.url, 10).hits.should == 0 }
23
+ describe '#hits' do
24
+ it { expect(hit_counter2.hits).to eq 10 }
18
25
  end
19
26
  end
20
27
  end
28
+ context 'with new URL' do
29
+ before { described_class.get 'www.cnn.com' }
21
30
 
22
- context 'when new URL' do
23
- before { HitCounter.get 'www.cnn.com' }
24
-
25
- describe 'document count' do
26
- specify { HitCounter.count.should == 2 }
31
+ describe '.count' do
32
+ it { expect(described_class.count).to eq 2 }
27
33
  end
28
34
 
35
+ context 'with blank starting count' do
36
+ describe '#hits' do
37
+ it do
38
+ expect(described_class.get('www.nytimes.com', nil).hits).to eq 0
39
+ end
40
+ end
41
+ end
29
42
  context 'with starting count 10' do
30
- describe 'hits' do
31
- specify { HitCounter.get('www.nytimes.com', 10).hits.should == 10 }
43
+ describe '#hits' do
44
+ it { expect(described_class.get('online.wsj.com', 10).hits).to eq 10 }
32
45
  end
33
46
  end
34
47
  end
48
+ context 'with JavaScript' do
49
+ before { described_class.delete_all }
50
+
51
+ subject { described_class.get(JAVASCRIPT_HACK) }
52
+
53
+ it do
54
+ subject.save
55
+ expect(subject).to be_invalid
56
+ end
57
+ end
35
58
  end
59
+ describe '.install' do
60
+ before do
61
+ expect_any_instance_of(Object).to receive(:system).twice.with match(/config|public/)
62
+ end
36
63
 
64
+ it('copies configuration files and images') { described_class.install }
65
+ end
37
66
  describe '#hits' do
38
- subject { @hit_counter.hits }
39
-
40
- it { should == 0 }
67
+ it { expect(subject.hits).to eq 0 }
41
68
 
42
69
  context 'when incremented' do
43
- before { @hit_counter.increment }
70
+ before { subject.increment }
44
71
 
45
- specify { @hit_counter.hits.should == 1 }
72
+ it { expect(subject.hits).to eq 1 }
46
73
  end
47
74
  end
75
+ describe '#hits=' do
76
+ context 'with JavaScript' do
77
+ before { subject.hits = JAVASCRIPT_HACK }
48
78
 
49
- describe '#image' do
50
- subject { @hit_counter.image '1' }
51
-
52
- it { should be_a Magick::Image }
53
- pending 'should reflect hits'
79
+ it { expect(subject.hits).to eq 0 }
80
+ end
54
81
  end
55
-
56
- describe '#normalize_style_number' do
57
- context 'when undefined' do
58
- it 'should return 0' do
59
- HitCounter.normalize_style_number(nil).should == 0
60
- end
82
+ describe '#image' do
83
+ context 'with a valid :style_number' do
84
+ it { expect(subject.image('1').filename).to eq "./public/images/digits/odometer/#{subject.hits}.png" }
61
85
  end
62
-
63
- context 'when within range' do
64
- it 'should return 0 for 1' do
65
- HitCounter.normalize_style_number('1').should == 0
86
+ context 'with JavaScript' do
87
+ it {
88
+ expect(subject.image(JAVASCRIPT_HACK).filename).to eq "./public/images/digits/odometer/#{subject.hits}.png"
89
+ }
90
+ end
91
+ end
92
+ describe '#url=' do
93
+ context 'with JavaScript' do
94
+ before do
95
+ subject.url = JAVASCRIPT_HACK
96
+ subject.save
66
97
  end
67
98
 
68
- it 'should return 2 for 3' do
69
- HitCounter.normalize_style_number('3').should == 2
70
- end
99
+ it { expect(subject).to be_invalid }
71
100
  end
72
-
73
- context 'when outside range' do
74
- context 'and negative' do
75
- context 'should return 2 for' do
76
- it -1 do
77
- HitCounter.normalize_style_number('-1').should == 2
78
- end
79
-
80
- it -31 do
81
- HitCounter.normalize_style_number('-31').should == 2
101
+ end
102
+ describe '.normalize_style_number' do
103
+ context 'with nil' do
104
+ it { expect(described_class.send(:normalize_style_number, nil)).to be_zero }
105
+ end
106
+ context 'with empty string' do
107
+ it { expect(described_class.send(:normalize_style_number, '')).to be_zero }
108
+ end
109
+ context 'with JavaScript' do
110
+ it { expect(described_class.send(:normalize_style_number, JAVASCRIPT_HACK)).to be_zero }
111
+ end
112
+ context 'with number in range' do
113
+ {
114
+ '1' => 0,
115
+ '3' => 2
116
+ }.each do |input, output|
117
+ context "with '#{input}'" do
118
+ it do
119
+ expect(described_class.send(:normalize_style_number, input)).to eq output
82
120
  end
83
121
  end
84
122
  end
85
-
86
- context 'and positive' do
87
- context 'should return 0 for' do
88
- it 4 do
89
- HitCounter.normalize_style_number('4').should == 0
90
- end
91
-
92
- it 34 do
93
- HitCounter.normalize_style_number('34').should == 0
123
+ end
124
+ context 'with number outside range' do
125
+ {
126
+ '-31' => 2,
127
+ '-1' => 2,
128
+ '4' => 0,
129
+ '34' => 0
130
+ }.each do |input, output|
131
+ context "with '#{input}'" do
132
+ it do
133
+ expect(described_class.send(:normalize_style_number, input)).to eq output
94
134
  end
95
135
  end
96
136
  end
97
137
  end
98
138
  end
99
-
100
- describe '#normalize_url' do
101
- context 'with "cnn.com"' do
102
- specify { HitCounter.normalize_url('cnn.com').should == 'http://cnn.com' }
103
- end
104
-
105
- context 'with "http://www.nytimes.com"' do
106
- specify { HitCounter.normalize_url('http://www.nytimes.com').should == 'http://www.nytimes.com' }
139
+ describe '.normalize_url' do
140
+ {
141
+ 'cnn.com' => 'http://cnn.com',
142
+ 'http://www.nytimes.com' => 'http://www.nytimes.com'
143
+ }.each do |input, output|
144
+ context "with '#{input}'" do
145
+ it { expect(described_class.send(:normalize_url, input)).to eq output }
146
+ end
107
147
  end
108
148
  end
109
- end
149
+ end
150
+ # rubocop:enable Metrics/BlockLength
data/spec/spec_helper.rb CHANGED
@@ -1,14 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
1
4
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ require 'addressable/uri'
7
+ require 'mongoid'
8
+ require 'RMagick'
3
9
  require 'rspec'
10
+
4
11
  require 'hit_counter'
5
12
 
6
- Mongoid::Config.from_hash 'database' => 'hit_counter'
7
- Mongoid.logger = false
13
+ Mongoid.load! 'config/mongoid.yml', :test
14
+ Mongo::Logger.logger.level = ::Logger::WARN
8
15
 
9
16
  # Stub Rails root during tests.
10
17
  module Rails
11
18
  def self.root
12
19
  '.'
13
20
  end
14
- end
21
+ end
22
+
23
+ require 'rake'
24
+
25
+ # load rake tasks
26
+ # https://dev.to/cassidycodes/how-to-test-rake-tasks-with-rspec-without-rails-3mhb
27
+ module TaskFormat
28
+ extend ActiveSupport::Concern
29
+ included do
30
+ let(:task_name) { self.class.top_level_description.sub(/\Arake /, '') }
31
+ let(:tasks) { Rake::Task }
32
+ # Make the Rake task available as `task` in your examples:
33
+ subject(:task) { tasks[task_name] }
34
+ end
35
+ end
36
+
37
+ RSpec.configure do |config|
38
+ config.before(:suite) do
39
+ Dir.glob('lib/tasks/*.rake').each { |r| Rake::DefaultLoader.new.load r }
40
+ end
41
+
42
+ # Tag Rake specs with `:task` metadata or put them in the spec/tasks dir
43
+ config.define_derived_metadata(file_path: %r{/spec/tasks/}) do |metadata|
44
+ metadata[:type] = :task
45
+ end
46
+
47
+ config.include TaskFormat, type: :task
48
+ end
49
+
50
+ # silence output
51
+ RSpec.configure do |config|
52
+ original_stderr = $stderr
53
+ original_stdout = $stdout
54
+ config.before(:all) do
55
+ # Redirect stderr and stdout
56
+ $stderr = File.open(File::NULL, 'w')
57
+ $stdout = File.open(File::NULL, 'w')
58
+ end
59
+ config.after(:all) do
60
+ $stderr = original_stderr
61
+ $stdout = original_stdout
62
+ end
63
+ end
data.tar.gz.sig ADDED
Binary file