rumble 0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 32a5250ec7ec28274e94ab016b9e547ed3060231
4
+ data.tar.gz: 8137684571e870ce3c7cee92f7ea663fc5e1e169
5
+ SHA512:
6
+ metadata.gz: 2191d5a14f74f4279eff43b12b0585b2880c7d00cbe7e5584d9fa04101498ea8c87105669ac65cbf424898fb977a1757862c63f0f359d1174abc3cf23c354874
7
+ data.tar.gz: e7beeb971cb67d5db7df0f3e7450592c00d6cc887dd67e4179d928f527383b53f9772aa113a08e383554dd827155f9112e3ce838983a9a35d3fc1ec016cf72aa
data/.0pdd.yml ADDED
@@ -0,0 +1,9 @@
1
+ errors:
2
+ - yegor256@gmail.com
3
+ # alerts:
4
+ # github:
5
+ # - yegor256
6
+
7
+ tags:
8
+ - pdd
9
+ - bug
data/.gitattributes ADDED
@@ -0,0 +1,7 @@
1
+ # Check out all text files in UNIX format, with LF as end of line
2
+ # Don't change this file. If you have any ideas about it, please
3
+ # submit a separate issue about it and we'll discuss.
4
+
5
+ * text=auto eol=lf
6
+ *.java ident
7
+ *.xml ident
@@ -0,0 +1,12 @@
1
+ Make sure the title of the issue explains the problem you are having. Also, the description of the issue must clearly explain what is broken, not what you want us to implement. Go through this checklist and make sure you answer "YES" to all points:
2
+
3
+ - You have all pre-requisites listed in README.md installed
4
+ - You are sure that you are not reporting a duplicate (search all issues)
5
+ - You say "is broken" or "doesn't work" in the title
6
+ - You tell us what you are trying to do
7
+ - You explain the results you are getting
8
+ - You suggest an alternative result you would like to see
9
+
10
+ This article will help you understand what we are looking for: http://www.yegor256.com/2014/11/24/principles-of-bug-tracking.html
11
+
12
+ Thank you for your contribution!
@@ -0,0 +1,11 @@
1
+ Many thanks for your contribution, we truly appreciate it. We will appreciate it even more, if you make sure that you can say "YES" to each point in this short checklist:
2
+
3
+ - You made a small amount of changes (less than 100 lines, less than 10 files)
4
+ - You made changes related to only one bug (create separate PRs for separate problems)
5
+ - You are ready to defend your changes (there will be a code review)
6
+ - You don't touch what you don't understand
7
+ - You ran the build locally and it passed
8
+
9
+ This article will help you understand what we are looking for: http://www.yegor256.com/2015/02/09/serious-code-reviewer.html
10
+
11
+ Thank you for your contribution!
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ coverage/
2
+ Gemfile.lock
3
+ .idea/
4
+ *.gem
5
+ .bundle/
6
+ .DS_Store
7
+ rdoc/
data/.pdd ADDED
@@ -0,0 +1,7 @@
1
+ --source=.
2
+ --verbose
3
+ --exclude target/**/*
4
+ --exclude coverage/**/*
5
+ --rule min-words:20
6
+ --rule min-estimate:15
7
+ --rule max-estimate:90
data/.rubocop.yml ADDED
@@ -0,0 +1,21 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'bin/**/*'
4
+ - 'assets/**/*'
5
+ DisplayCopNames: true
6
+ TargetRubyVersion: 2.2
7
+
8
+ Metrics/CyclomaticComplexity:
9
+ Max: 10
10
+ Metrics/MethodLength:
11
+ Enabled: false
12
+ Style/MultilineMethodCallIndentation:
13
+ Enabled: false
14
+ Metrics/AbcSize:
15
+ Enabled: false
16
+ Metrics/BlockLength:
17
+ Max: 50
18
+ Metrics/PerceivedComplexity:
19
+ Max: 10
20
+ Style/MultilineTernaryOperator:
21
+ Enabled: false
data/.rultor.yml ADDED
@@ -0,0 +1,30 @@
1
+ assets:
2
+ rubygems.yml: zerocracy/home#assets/rubygems.yml
3
+ s3cfg: zerocracy/home#assets/s3cfg
4
+ install: |
5
+ sudo apt-get -y update
6
+ sudo gem install pdd
7
+ release:
8
+ script: |-
9
+ bundle install
10
+ rake
11
+ rm -rf *.gem
12
+ sed -i "s/1\.0\.snapshot/${tag}/g" lib/rumble/version.rb
13
+ git add lib/rumble/version.rb
14
+ git commit -m "version set to ${tag}"
15
+ gem build rumble.gemspec
16
+ chmod 0600 ../rubygems.yml
17
+ gem push *.gem --config-file ../rubygems.yml
18
+ commanders:
19
+ - yegor256
20
+ architect:
21
+ - yegor256
22
+ merge:
23
+ script: |-
24
+ bundle install
25
+ rake
26
+ pdd
27
+ deploy:
28
+ script: |-
29
+ echo "There is nothing to deploy"
30
+ exit -1
data/.simplecov ADDED
@@ -0,0 +1,38 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ if Gem.win_platform? then
22
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
23
+ SimpleCov::Formatter::HTMLFormatter
24
+ ]
25
+ SimpleCov.start do
26
+ add_filter "/test/"
27
+ add_filter "/features/"
28
+ end
29
+ else
30
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
31
+ [SimpleCov::Formatter::HTMLFormatter]
32
+ )
33
+ SimpleCov.start do
34
+ add_filter "/test/"
35
+ add_filter "/features/"
36
+ minimum_coverage 80
37
+ end
38
+ end
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ cache: bundler
5
+ branches:
6
+ only:
7
+ - master
8
+ install:
9
+ - travis_retry bundle update
10
+ script:
11
+ - rake
12
+ after_success:
13
+ - "bash <(curl -s https://codecov.io/bash)"
data/Gemfile ADDED
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ source 'https://rubygems.org'
22
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2018 Yegor Bugayenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ [![EO principles respected here](http://www.elegantobjects.org/badge.svg)](http://www.elegantobjects.org)
2
+ [![Managed by Zerocracy](https://www.0crat.com/badge/C3RFVLU72.svg)](https://www.0crat.com/p/C3RFVLU72)
3
+ [![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/rumble)](http://www.rultor.com/p/yegor256/rumble)
4
+ [![We recommend RubyMine](http://www.elegantobjects.org/rubymine.svg)](https://www.jetbrains.com/ruby/)
5
+
6
+ [![Build Status](https://travis-ci.org/yegor256/rumble.svg)](https://travis-ci.org/yegor256/rumble)
7
+ [![Build status](https://ci.appveyor.com/api/projects/status/orvfo2qgmd1d7a2i?svg=true)](https://ci.appveyor.com/project/yegor256/rumble)
8
+ [![PDD status](http://www.0pdd.com/svg?name=yegor256/rumble)](http://www.0pdd.com/p?name=yegor256/rumble)
9
+ [![Gem Version](https://badge.fury.io/rb/rumble.svg)](http://badge.fury.io/rb/rumble)
10
+ [![Dependency Status](https://gemnasium.com/yegor256/rumble.svg)](https://gemnasium.com/yegor256/rumble)
11
+ [![Code Climate](http://img.shields.io/codeclimate/github/yegor256/rumble.svg)](https://codeclimate.com/github/yegor256/rumble)
12
+ [![Test Coverage](https://img.shields.io/codecov/c/github/yegor256/rumble.svg)](https://codecov.io/github/yegor256/rumble?branch=master)
13
+
14
+ ## What this is for?
15
+
16
+ This command line tool helps you send newsletters.
17
+
18
+ ## How to install?
19
+
20
+ Install it first:
21
+
22
+ ```bash
23
+ $ gem install rumble
24
+ ```
25
+
26
+ ## How to run?
27
+
28
+ Run it locally and read its output:
29
+
30
+ ```bash
31
+ $ rumble --help
32
+ ```
33
+
34
+ ## How to contribute?
35
+
36
+ Just submit a pull request. Make sure `rake` passes.
37
+
38
+ ## License
39
+
40
+ (The MIT License)
41
+
42
+ Copyright (c) 2018 Yegor Bugayenko
43
+
44
+ Permission is hereby granted, free of charge, to any person obtaining a copy
45
+ of this software and associated documentation files (the 'Software'), to deal
46
+ in the Software without restriction, including without limitation the rights
47
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48
+ copies of the Software, and to permit persons to whom the Software is
49
+ furnished to do so, subject to the following conditions:
50
+
51
+ The above copyright notice and this permission notice shall be included in all
52
+ copies or substantial portions of the Software.
53
+
54
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
60
+ SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,75 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ require 'rubygems'
22
+ require 'rake'
23
+ require 'rdoc'
24
+ require 'rake/clean'
25
+
26
+ def name
27
+ @name ||= File.basename(Dir['*.gemspec'].first, '.*')
28
+ end
29
+
30
+ def version
31
+ Gem::Specification.load(Dir['*.gemspec'].first).version
32
+ end
33
+
34
+ task default: %i[clean test features rubocop copyright]
35
+
36
+ require 'rake/testtask'
37
+ desc 'Run all unit tests'
38
+ Rake::TestTask.new(:test) do |test|
39
+ Rake::Cleaner.cleanup_files(['coverage'])
40
+ test.libs << 'lib' << 'test'
41
+ test.pattern = 'test/**/test_*.rb'
42
+ test.verbose = false
43
+ end
44
+
45
+ require 'rdoc/task'
46
+ desc 'Build RDoc documentation'
47
+ Rake::RDocTask.new do |rdoc|
48
+ rdoc.rdoc_dir = 'rdoc'
49
+ rdoc.title = "#{name} #{version}"
50
+ rdoc.rdoc_files.include('README*')
51
+ rdoc.rdoc_files.include('lib/**/*.rb')
52
+ end
53
+
54
+ require 'rubocop/rake_task'
55
+ desc 'Run RuboCop on all directories'
56
+ RuboCop::RakeTask.new(:rubocop) do |task|
57
+ task.fail_on_error = true
58
+ task.requires << 'rubocop-rspec'
59
+ end
60
+
61
+ require 'cucumber/rake/task'
62
+ Cucumber::Rake::Task.new(:features) do
63
+ Rake::Cleaner.cleanup_files(['coverage'])
64
+ end
65
+ Cucumber::Rake::Task.new(:'features:html') do |t|
66
+ t.profile = 'html_report'
67
+ end
68
+
69
+ task :copyright do
70
+ sh "grep -q -r '#{Date.today.strftime('%Y')}' \
71
+ --include '*.rb' \
72
+ --include '*.txt' \
73
+ --include 'Rakefile' \
74
+ ."
75
+ end
data/appveyor.yml ADDED
@@ -0,0 +1,21 @@
1
+ version: '{build}'
2
+ skip_tags: true
3
+ clone_depth: 10
4
+ branches:
5
+ only:
6
+ - master
7
+ except:
8
+ - gh-pages
9
+ os: Windows Server 2012
10
+ install:
11
+ - cmd: SET PATH=C:\Ruby23-x64\bin;%PATH%
12
+ - cmd: ruby --version
13
+ - cmd: git --version
14
+ build_script:
15
+ - bundle update
16
+ - bundle install
17
+ test_script:
18
+ - rake
19
+ cache:
20
+ - C:\Ruby200\bin -> rumble.gemspec
21
+ - C:\Ruby200\lib\ruby\gems\2.0.0 -> rumble.gemspec
data/bin/rumble ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (c) 2018 Yegor Bugayenko
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the 'Software'), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ # SOFTWARE.
21
+
22
+ STDOUT.sync = true
23
+
24
+ require 'slop'
25
+ require 'mail'
26
+ require_relative '../lib/rumble'
27
+ require_relative '../lib/rumble/version'
28
+
29
+ begin
30
+ args = []
31
+ config = File.expand_path('~/.rumble')
32
+ if File.exist?(config)
33
+ body = File.read(config)
34
+ extra = body.split(/[\r\n]+/).map(&:strip)
35
+ args += extra
36
+ puts "Found #{body.split(/\n/).length} lines in #{config}"
37
+ else
38
+ puts "Default config file #{config} not found"
39
+ end
40
+ args += ARGV
41
+
42
+ begin
43
+ opts = Slop.parse(args, strict: true, help: true) do |o|
44
+ o.banner = "Usage (#{Rumble::VERSION}): rumble [options]"
45
+ o.bool '--help', 'Show these instructions' do
46
+ puts o
47
+ exit
48
+ end
49
+ o.bool '-v', '--version', 'Show current version' do
50
+ puts Rumble::VERSION
51
+ exit
52
+ end
53
+ o.bool '--dry', 'Dry run, no emails will be delivered'
54
+ o.string '--from',
55
+ 'Full SMTP From field, e.g. "John Doe <jd@example.com>"',
56
+ required: true
57
+ o.string '--host', 'SMTP host name', required: true
58
+ o.string '--port', 'SMTP port number', default: 25
59
+ o.string '--user', 'SMTP user name', required: true
60
+ o.string '--password', 'SMTP password', required: true
61
+ o.string '--subject', 'Email subject', required: true
62
+ o.string '--letter', 'File name with Liquid template', required: true
63
+ o.string '--targets', 'File name with emails and names'
64
+ o.string '--resume', 'Email address from which we should resume'
65
+ o.string '--skip', 'File name with emails that opted-out (black list)'
66
+ o.string '--test', 'Email address to use instead of the real user list'
67
+ end
68
+ rescue Slop::Error => ex
69
+ raise StandardError, "#{ex.message}, try --help"
70
+ end
71
+
72
+ Encoding.default_external = Encoding::UTF_8
73
+ Encoding.default_internal = Encoding::UTF_8
74
+
75
+ Mail.defaults do
76
+ delivery_method :smtp, {
77
+ :address => opts[:host],
78
+ :port => opts[:port],
79
+ :user_name => opts[:user],
80
+ :password => opts[:password],
81
+ :enable_starttls_auto => true
82
+ }
83
+ end
84
+
85
+ Rumble::CLI.new(opts).send
86
+
87
+ rescue StandardError => ex
88
+ puts "#{Rainbow('ERROR').red} (#{ex.class.name}): #{ex.message}"
89
+ exit(255)
90
+ end
data/cucumber.yml ADDED
@@ -0,0 +1,3 @@
1
+ default: --format pretty
2
+ travis: --format progress
3
+ html_report: --format progress --format html --out=features_report.html
@@ -0,0 +1,22 @@
1
+ Feature: Command Line Processing
2
+ As a newsletter author I want to be able to send a newsletter
3
+
4
+ Scenario: Help can be printed
5
+ When I run bin/rumble with "--help"
6
+ Then Exit code is zero
7
+ And Stdout contains "--help"
8
+
9
+ Scenario: Version can be printed
10
+ When I run bin/rumble with "--version"
11
+ Then Exit code is zero
12
+
13
+ Scenario: Sending test email
14
+ Given I have a "a.liquid" file with content:
15
+ """
16
+ Hi, {{ first }}
17
+ How are you?
18
+
19
+ """
20
+ When I run bin/rumble with "--test yegor256@gmail.com --host test --user test --password test --subject test --letter a.liquid --from me@example.com --dry"
21
+ Then Stdout contains "Sent 1 email"
22
+ And Exit code is zero
@@ -0,0 +1,24 @@
1
+ Feature: Gem Package
2
+ As a source code writer I want to be able to
3
+ package the Gem into .gem file
4
+
5
+ Scenario: Gem can be packaged
6
+ Given It is Unix
7
+ Given I have a "execs.rb" file with content:
8
+ """
9
+ #!/usr/bin/env ruby
10
+ require 'rubygems'
11
+ spec = Gem::Specification::load('./spec.rb')
12
+ if spec.executables.empty?
13
+ fail 'no executables: ' + File.read('./spec.rb')
14
+ end
15
+ """
16
+ When I run bash with:
17
+ """
18
+ cd rumble
19
+ gem build rumble.gemspec
20
+ gem specification --ruby rumble-*.gem > ../spec.rb
21
+ cd ..
22
+ ruby execs.rb
23
+ """
24
+ Then Exit code is zero
@@ -0,0 +1,92 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ require 'nokogiri'
22
+ require 'tmpdir'
23
+ require 'slop'
24
+ require 'English'
25
+ require_relative '../../lib/rumble'
26
+
27
+ Before do
28
+ @cwd = Dir.pwd
29
+ @dir = Dir.mktmpdir('test')
30
+ FileUtils.mkdir_p(@dir) unless File.exist?(@dir)
31
+ Dir.chdir(@dir)
32
+ @opts = Slop.parse ['-v', '-s', @dir] do |o|
33
+ o.bool '-v', '--verbose'
34
+ o.string '-s', '--source'
35
+ end
36
+ end
37
+
38
+ After do
39
+ Dir.chdir(@cwd)
40
+ FileUtils.rm_rf(@dir) if File.exist?(@dir)
41
+ end
42
+
43
+ Given(/^I have a "([^"]*)" file with content:$/) do |file, text|
44
+ FileUtils.mkdir_p(File.dirname(file)) unless File.exist?(file)
45
+ File.open(file, 'w') do |f|
46
+ f.write(text.gsub(/\\xFF/, 0xFF.chr))
47
+ end
48
+ end
49
+
50
+ When(%r{^I run bin/rumble with "([^"]*)"$}) do |arg|
51
+ home = File.join(File.dirname(__FILE__), '../..')
52
+ @stdout = `ruby -I#{home}/lib #{home}/bin/rumble #{arg}`
53
+ @exitstatus = $CHILD_STATUS.exitstatus
54
+ end
55
+
56
+ Then(/^Stdout contains "([^"]*)"$/) do |txt|
57
+ unless @stdout.include?(txt)
58
+ raise "STDOUT doesn't contain '#{txt}':\n#{@stdout}"
59
+ end
60
+ end
61
+
62
+ Then(/^Stdout is empty$/) do
63
+ raise "STDOUT is not empty:\n#{@stdout}" unless @stdout == ''
64
+ end
65
+
66
+ Then(/^Exit code is zero$/) do
67
+ raise "Non-zero exit #{@exitstatus}:\n#{@stdout}" unless @exitstatus.zero?
68
+ end
69
+
70
+ Then(/^Exit code is not zero$/) do
71
+ raise 'Zero exit code' if @exitstatus.zero?
72
+ end
73
+
74
+ When(/^I run bash with "([^"]*)"$/) do |text|
75
+ FileUtils.copy_entry(@cwd, File.join(@dir, 'rumble'))
76
+ @stdout = `#{text}`
77
+ @exitstatus = $CHILD_STATUS.exitstatus
78
+ end
79
+
80
+ When(/^I run bash with:$/) do |text|
81
+ FileUtils.copy_entry(@cwd, File.join(@dir, 'rumble'))
82
+ @stdout = `#{text}`
83
+ @exitstatus = $CHILD_STATUS.exitstatus
84
+ end
85
+
86
+ Given(/^It is Unix$/) do
87
+ pending if Gem.win_platform?
88
+ end
89
+
90
+ Given(/^It is Windows$/) do
91
+ pending unless Gem.win_platform?
92
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ require 'simplecov'
22
+ require_relative '../../lib/rumble'
data/lib/rumble.rb ADDED
@@ -0,0 +1,106 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ require 'mail'
22
+ require 'uuidtools'
23
+ require 'liquid'
24
+ require 'redcarpet'
25
+ require 'redcarpet/render_strip'
26
+ require 'rainbow'
27
+ require_relative 'rumble/version'
28
+
29
+ # Rumble main script.
30
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
31
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
32
+ # License:: MIT
33
+ module Rumble
34
+ # Command line interface.
35
+ class CLI
36
+ def initialize(opts)
37
+ @opts = opts
38
+ end
39
+
40
+ def send
41
+ letter = Liquid::Template.parse(
42
+ File.read(File.expand_path(@opts[:letter]))
43
+ )
44
+ skip = @opts[:skip] ? File.readlines(@opts[:skip]).map(&:strip) : []
45
+ emails = @opts[:test] ?
46
+ ["John,Doe,#{@opts[:test]}"]
47
+ : File.readlines(@opts[:targets]).map(&:strip).reject(&:empty?)
48
+ total = 0
49
+ sent = []
50
+ ignore = !@opts[:resume].nil?
51
+ from = @opts[:from].strip
52
+ puts "Sending #{emails.length} email(s) as #{from}"
53
+ domain = from.strip.gsub(/^.+@|>$/)
54
+ emails.each do |line|
55
+ first, last, email = line.split(',')
56
+ email = email.strip.downcase
57
+ name = "#{first} #{last}".strip
58
+ address = email
59
+ address = "#{name} <#{email}>" unless name.empty?
60
+ print "Sending to #{address}... "
61
+ markdown = letter.render(
62
+ 'email' => email, 'first' => first, 'last' => last
63
+ )
64
+ html = Redcarpet::Markdown.new(Redcarpet::Render::HTML)
65
+ .render(markdown)
66
+ text = Redcarpet::Markdown.new(Redcarpet::Render::StripDown)
67
+ .render(markdown)
68
+ if ignore
69
+ if opts[:resume] != email
70
+ puts "ignored, waiting for #{opts[:resume]}"
71
+ next
72
+ end
73
+ ignore = false
74
+ end
75
+ if skip.include?(email)
76
+ puts Rainbow('skipped').red
77
+ next
78
+ end
79
+ if sent.include?(email)
80
+ puts Rainbow('duplicate').red
81
+ next
82
+ end
83
+ subject = @opts[:subject]
84
+ mail = Mail.new do
85
+ from from
86
+ to address
87
+ subject subject
88
+ message_id "<#{UUIDTools::UUID.random_create}@#{domain}>"
89
+ text_part do
90
+ content_type 'text/plain; charset=UTF-8'
91
+ body text
92
+ end
93
+ html_part do
94
+ content_type 'text/html; charset=UTF-8'
95
+ body html
96
+ end
97
+ end
98
+ mail.deliver! unless @opts[:dry]
99
+ sent.push(email)
100
+ total += 1
101
+ puts "#{Rainbow('done').green} ##{total}"
102
+ end
103
+ puts "Sent #{sent.size} emails"
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ # Rumble main module.
22
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
23
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
24
+ # License:: MIT
25
+ module Rumble
26
+ VERSION = '0.1'.freeze
27
+ end
data/rumble.gemspec ADDED
@@ -0,0 +1,61 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ require 'English'
22
+
23
+ lib = File.expand_path('../lib', __FILE__)
24
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
25
+ require_relative 'lib/rumble/version'
26
+
27
+ Gem::Specification.new do |s|
28
+ s.specification_version = 2 if s.respond_to? :specification_version=
29
+ if s.respond_to? :required_rubygems_version=
30
+ s.required_rubygems_version = Gem::Requirement.new('>= 0')
31
+ end
32
+ s.rubygems_version = '2.2'
33
+ s.required_ruby_version = '>= 2.2'
34
+ s.name = 'rumble'
35
+ s.version = Rumble::VERSION
36
+ s.license = 'MIT'
37
+ s.summary = 'Command Line Newsletter Sending Tool'
38
+ s.description = 'Sends newsletters to recipients'
39
+ s.authors = ['Yegor Bugayenko']
40
+ s.email = 'yegor256@gmail.com'
41
+ s.homepage = 'http://github.com/yegor256/rumble'
42
+ s.files = `git ls-files`.split($RS)
43
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
44
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
45
+ s.rdoc_options = ['--charset=UTF-8']
46
+ s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
47
+ s.add_runtime_dependency 'liquid', '~>4.0.0'
48
+ s.add_runtime_dependency 'mail', '~>2.7.0'
49
+ s.add_runtime_dependency 'rainbow', '~>3.0'
50
+ s.add_runtime_dependency 'redcarpet', '~>3.4.0'
51
+ s.add_runtime_dependency 'slop', '~>4.4'
52
+ s.add_runtime_dependency 'uuidtools', '~>2.1.5'
53
+ s.add_development_dependency 'codecov', '0.1.10'
54
+ s.add_development_dependency 'cucumber', '1.3.17'
55
+ s.add_development_dependency 'minitest', '5.5.0'
56
+ s.add_development_dependency 'rake', '12.0.0'
57
+ s.add_development_dependency 'rdoc', '4.2.0'
58
+ s.add_development_dependency 'rspec-rails', '3.1.0'
59
+ s.add_development_dependency 'rubocop', '0.52.0'
60
+ s.add_development_dependency 'rubocop-rspec', '1.5.1'
61
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ STDOUT.sync = true
22
+
23
+ require 'simplecov'
24
+ SimpleCov.start
25
+ if ENV['CI'] == 'true'
26
+ require 'codecov'
27
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
28
+ end
29
+
30
+ require 'minitest/autorun'
31
+ require_relative '../lib/rumble'
@@ -0,0 +1,44 @@
1
+ # Copyright (c) 2018 Yegor Bugayenko
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the 'Software'), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all
11
+ # copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ # SOFTWARE.
20
+
21
+ require 'minitest/autorun'
22
+ require 'tmpdir'
23
+ require 'slop'
24
+ require_relative '../lib/rumble'
25
+
26
+ # Rumble main module test.
27
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
28
+ # Copyright:: Copyright (c) 2018 Yegor Bugayenko
29
+ # License:: MIT
30
+ class TestRumble < Minitest::Test
31
+ def test_basic
32
+ Dir.mktmpdir 'test' do |dir|
33
+ letter = File.join(dir, 'letter.liquid')
34
+ File.write(letter, 'Hi {{first}}, how are you?')
35
+ Rumble::CLI.new(
36
+ dry: true,
37
+ test: 'test@yegor256.com',
38
+ letter: letter,
39
+ host: 'localhost',
40
+ from: 'Yegor Bugayenko <yegor256@gmail.com>'
41
+ ).send
42
+ end
43
+ end
44
+ end
metadata ADDED
@@ -0,0 +1,275 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rumble
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Yegor Bugayenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: liquid
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: mail
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.7.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.7.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rainbow
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: redcarpet
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.4.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.4.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: slop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.4'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: uuidtools
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 2.1.5
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.1.5
97
+ - !ruby/object:Gem::Dependency
98
+ name: codecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 0.1.10
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 0.1.10
111
+ - !ruby/object:Gem::Dependency
112
+ name: cucumber
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '='
116
+ - !ruby/object:Gem::Version
117
+ version: 1.3.17
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '='
123
+ - !ruby/object:Gem::Version
124
+ version: 1.3.17
125
+ - !ruby/object:Gem::Dependency
126
+ name: minitest
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '='
130
+ - !ruby/object:Gem::Version
131
+ version: 5.5.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '='
137
+ - !ruby/object:Gem::Version
138
+ version: 5.5.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: rake
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '='
144
+ - !ruby/object:Gem::Version
145
+ version: 12.0.0
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '='
151
+ - !ruby/object:Gem::Version
152
+ version: 12.0.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: rdoc
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '='
158
+ - !ruby/object:Gem::Version
159
+ version: 4.2.0
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '='
165
+ - !ruby/object:Gem::Version
166
+ version: 4.2.0
167
+ - !ruby/object:Gem::Dependency
168
+ name: rspec-rails
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - '='
172
+ - !ruby/object:Gem::Version
173
+ version: 3.1.0
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - '='
179
+ - !ruby/object:Gem::Version
180
+ version: 3.1.0
181
+ - !ruby/object:Gem::Dependency
182
+ name: rubocop
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - '='
186
+ - !ruby/object:Gem::Version
187
+ version: 0.52.0
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - '='
193
+ - !ruby/object:Gem::Version
194
+ version: 0.52.0
195
+ - !ruby/object:Gem::Dependency
196
+ name: rubocop-rspec
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - '='
200
+ - !ruby/object:Gem::Version
201
+ version: 1.5.1
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - '='
207
+ - !ruby/object:Gem::Version
208
+ version: 1.5.1
209
+ description: Sends newsletters to recipients
210
+ email: yegor256@gmail.com
211
+ executables:
212
+ - rumble
213
+ extensions: []
214
+ extra_rdoc_files:
215
+ - README.md
216
+ - LICENSE.txt
217
+ files:
218
+ - ".0pdd.yml"
219
+ - ".gitattributes"
220
+ - ".github/ISSUE_TEMPLATE.md"
221
+ - ".github/PULL_REQUEST_TEMPLATE.md"
222
+ - ".gitignore"
223
+ - ".pdd"
224
+ - ".rubocop.yml"
225
+ - ".rultor.yml"
226
+ - ".simplecov"
227
+ - ".travis.yml"
228
+ - Gemfile
229
+ - LICENSE.txt
230
+ - README.md
231
+ - Rakefile
232
+ - appveyor.yml
233
+ - bin/rumble
234
+ - cucumber.yml
235
+ - features/cli.feature
236
+ - features/gem_package.feature
237
+ - features/step_definitions/steps.rb
238
+ - features/support/env.rb
239
+ - lib/rumble.rb
240
+ - lib/rumble/version.rb
241
+ - rumble.gemspec
242
+ - test/test__helper.rb
243
+ - test/test_rumble.rb
244
+ homepage: http://github.com/yegor256/rumble
245
+ licenses:
246
+ - MIT
247
+ metadata: {}
248
+ post_install_message:
249
+ rdoc_options:
250
+ - "--charset=UTF-8"
251
+ require_paths:
252
+ - lib
253
+ required_ruby_version: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '2.2'
258
+ required_rubygems_version: !ruby/object:Gem::Requirement
259
+ requirements:
260
+ - - ">="
261
+ - !ruby/object:Gem::Version
262
+ version: '0'
263
+ requirements: []
264
+ rubyforge_project:
265
+ rubygems_version: 2.6.8
266
+ signing_key:
267
+ specification_version: 2
268
+ summary: Command Line Newsletter Sending Tool
269
+ test_files:
270
+ - features/cli.feature
271
+ - features/gem_package.feature
272
+ - features/step_definitions/steps.rb
273
+ - features/support/env.rb
274
+ - test/test__helper.rb
275
+ - test/test_rumble.rb