le_meme 0.0.8 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d259d15403afedfcf9afff3d29004ea4d778f180
4
- data.tar.gz: 509820a6f6e562852d82e0494ad3e4e2f81be81e
3
+ metadata.gz: 855301d19080a1db16d6df06321f7dbfcc8bb712
4
+ data.tar.gz: 0596203d86d7345eda25226571cec379b6b12ac0
5
5
  SHA512:
6
- metadata.gz: a432b9ba98e2390e5409a1dd327a4d6ee3b9d059c3b76b2b0185e71e4833e16841a394e175efc9b8509d668abd9a1473d0ed2176b7b84be3b562e0b2a3c202a6
7
- data.tar.gz: 82c70074224e66c354f074d1786747c1d820756371c7dd403337136a994ddaede68f2a83094f64d2821614eb185a7bf4bff806099530e01684968e66449e017c
6
+ metadata.gz: 0bdd71930c20ecd3b8aa3bea58e193db74e4eeddd69c2a3af25db7111e3e1538163b52919be9bc9c0a0dd95d7c0ce7014ca4353224fdc43fe6f707062366e891
7
+ data.tar.gz: de6f304bbaeca7733b128b49717b9e012af2d062b9a0d7d3d06760a04a0302f444846f58afcaba4a5967fa4dee60ebc87e66d4a4a6128093b23043763d2cf550
@@ -0,0 +1,5 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.1
3
+
4
+ Metrics/LineLength:
5
+ Enabled: false
data/README.md CHANGED
@@ -37,15 +37,20 @@ Should be straightforward enough for even the dankest memer.
37
37
  ### I want to make memes in my ruby application
38
38
  Easy enough!
39
39
 
40
+ #### Using a template
40
41
  ```ruby
41
42
  require 'le_meme'
43
+ LeMeme::MemeLib.new_with_default_memes.meme(template: 'maymay', top: 'Top text', bottom: 'Bottom Text').to_file
44
+ ```
42
45
 
43
- meme = LeMeme.new
46
+ #### Using any old image
44
47
 
45
- meme.m(top: 'dank memes!', bottom: 'bottom text')
48
+ ```ruby
49
+ require 'le_meme'
50
+ LeMeme::Meme.new('~/Desktop/to_be_memed.jpg', top: 'Top text', bottom: 'bottom text').to_file
46
51
  ```
47
52
 
48
- See the [docs](http://www.rubydoc.info/gems/le_meme) for all the shrektastic details
53
+ See the [docs](http://www.rubydoc.info/gems/le_meme) for all the memetastic details
49
54
 
50
55
  ## Contributing
51
56
 
@@ -60,12 +65,7 @@ Because the world needs more dank memes!
60
65
 
61
66
  Actually, because I wanted to take some time and clean up the core of [memebot](http://github.com/paradox460/memebot), and figured making the essential meme generation a gem was the best way to do it. Now I can spam my coworkers with memes in hipchat as well.
62
67
 
63
- ## TODO
64
- - [ ] Allow dynamic additon of memes to internal memecache
65
- - [ ] Test `meme` binary
66
-
67
- ## License
68
-
68
+ ## LICENSE
69
69
  ```
70
70
  Copyright (c) 2015 Jeff Sandberg
71
71
 
data/Rakefile CHANGED
@@ -5,4 +5,4 @@ RSpec::Core::RakeTask.new(:spec) do |task|
5
5
  task.rspec_opts = ['--color', '--format', 'd']
6
6
  end
7
7
 
8
- task :default => :spec
8
+ task default: :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'le_meme'
5
+ require 'pry'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ Pry.start
data/bin/meme CHANGED
@@ -1,61 +1,90 @@
1
- #!/Usr/bin/env ruby
1
+ #!/usr/bin/env ruby
2
2
 
3
+ require 'bundler/setup'
3
4
  require 'le_meme'
4
- require 'slop'
5
+ require 'optparse'
6
+ require 'pry'
5
7
 
6
- memegen = LeMeme.new
7
- opts = Slop.new(strict: true, help: true) do
8
- banner <<-HEREDOC
8
+ options = {}
9
+
10
+ if ARGV.empty?
11
+ exit(0) unless $stdout.tty?
12
+ $stdout.puts 'Usage: meme [options] [top-text] [bottom-text]'
13
+ $stdout.puts ' run -h for help'
14
+ exit(0)
15
+ end
16
+
17
+ memelib = LeMeme::MemeLib.new_with_default_memes
18
+
19
+ OptionParser.new do |opts|
20
+ opts.banner = <<-HEREDOC
9
21
  Usage: meme [options] [top-text] [bottom-text]
10
22
 
11
23
  Top and bottom may be set by the last 2 unprefixed arguments, or by their respective flags.
12
24
  If you don't specify a meme, either via image path or by template, we'll pick one for you.
13
25
  HEREDOC
14
- separator '---'
15
-
16
- on 't', 'top=', 'top text'
17
- on 'b', 'bottom=', 'bottom text.'
18
- on 'm', 'meme=', 'meme template you want to use, see --templates'
19
- on 'p', 'path=', 'path to an image to use for the meme'
20
- on 'w', 'watermark=', 'text to watermark the image'
21
- on 'o', 'outpath=', 'path to save the final meme to'
22
- on 'O', 'open', "Open the file in your system's default image viewer"
23
-
24
- on 'templates', 'list all the meme templates' do
25
- puts memegen.memes.keys.join("\n")
26
- exit
26
+
27
+ opts.separator '---'
28
+
29
+ opts.on('-tTOP', '--top=TOP', 'top text') do |top|
30
+ options[:top] = top
27
31
  end
28
- on 'v', 'version', 'display the current version' do
29
- $stdout.puts LeMeme::VERSION
30
- exit
32
+ opts.on('-bBOTTOM', '--bottom=BOTTOM', 'bottom text') do |bottom|
33
+ options[:bottom] = bottom
34
+ end
35
+ opts.on('-wWATERMARK', '--watermark=WATERMARK', 'watermark text') do |watermark|
36
+ options[:watermark] = watermark
31
37
  end
32
- end
33
- if ARGV.empty?
34
- $stdout.puts opts if $stdout.tty?
35
- exit(0)
36
- end
37
38
 
38
- opts.parse!
39
+ opts.separator ''
39
40
 
40
- top = opts[:top] || ARGV[0]
41
- bottom = opts[:bottom] || ARGV[1]
41
+ opts.on('-mTEMPLATE', '--meme=TEMPLATE', 'meme template you want to use. See --templates for list') do |template|
42
+ options[:template] = template
43
+ end
42
44
 
45
+ opts.on('-pPATH', '--path=PATH', 'path to image file to use') do |path|
46
+ options[:path] = path
47
+ end
48
+ opts.on('-oPATH', '--outpath=PATH', 'path to save generated meme') do |path|
49
+ options[:outpath] = path
50
+ end
51
+ opts.on('-O', '--open', 'open when finished') do |o|
52
+ options[:open] = o
53
+ end
43
54
 
44
- if opts[:path]
45
- output = memegen.meme(path: opts[:path], top: top, bottom: bottom, watermark: opts[:watermark], outpath: opts[:outpath])
46
- else
47
- name = opts[:meme].strip if opts[:meme]
48
- output = memegen.fast_meme(name: name, top: top, bottom: bottom, watermark: opts[:watermark], outpath: opts[:outpath])
49
- end
55
+ opts.separator ''
56
+
57
+ opts.on('--templates', 'list all the meme templates') do
58
+ puts memelib.memes.keys.join("\n")
59
+ exit(0)
60
+ end
61
+
62
+ opts.on('-h', '--help', 'prints this help') do
63
+ puts opts
64
+ exit(0)
65
+ end
66
+ end.parse!
67
+
68
+ top = options[:top] || ARGV[0]
69
+ bottom = options[:bottom] || ARGV[1]
70
+
71
+ meme = if options[:path]
72
+ LeMeme::Meme.new(options[:path], top: top, bottom: bottom, watermark: options[:watermark])
73
+ else
74
+ template = options[:template].nil? ? nil : options[:template].strip
75
+ memelib.meme(template: template, top: top, bottom: bottom, watermark: options[:watermark])
76
+ end
77
+
78
+ output = meme.to_file(options[:outpath]).path
50
79
 
51
- if opts[:open]
80
+ if options[:open]
52
81
  case RbConfig::CONFIG['host_os']
53
82
  when /mswin|mingw|cygwin/
54
- `start #{output}`
83
+ `start '#{output}'`
55
84
  when /darwin/
56
- `open -F #{output}`
85
+ `open -F '#{output}'`
57
86
  when /linux|bsd/
58
- `xdg-open #{output}`
87
+ `xdg-open '#{output}'`
59
88
  else
60
89
  $stderr.puts "Sorry, don't know how to open on your system! (#{RbConfig::Config['host_os']})"
61
90
  end
@@ -16,14 +16,16 @@ Gem::Specification.new do |spec|
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
- spec.add_development_dependency 'bundler', '~> 1.7'
22
- spec.add_development_dependency 'rake', '~> 10.0'
23
- spec.add_development_dependency 'pry', '~> 0.10'
24
- spec.add_development_dependency 'rspec', '~> 3.1'
21
+ spec.required_ruby_version = '>= 2.1'
25
22
 
26
- spec.add_runtime_dependency 'rmagick', '~> 2.13'
23
+ spec.add_development_dependency 'bundler'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'pry'
26
+ spec.add_development_dependency 'pry-byebug'
27
+ spec.add_development_dependency 'rspec'
28
+
29
+ spec.add_runtime_dependency 'rmagick', '~> 2.15'
27
30
  spec.add_runtime_dependency 'word_wrapper', '~> 0.5.0'
28
- spec.add_runtime_dependency 'slop', '~> 3.6'
29
31
  end
@@ -1,184 +1,10 @@
1
- require 'le_meme/version'
2
1
  require 'rmagick'
3
2
  require 'word_wrapper'
4
- require 'pathname'
5
-
6
- # Create some dank memes
7
- #
8
- # @author Jeff Sandberg <paradox460@gmail.com>
9
- class LeMeme
10
- VALID_IMAGE_EXTENSIONS = /\.(jp[e]?g|png|gif)$/i
11
-
12
- attr_reader :memes
13
-
14
- # Create a new instance of LeMeme, for generating memes.
15
- #
16
- # @param [Array] Directories of images you want the gem to know about. Scrapes images in said directory
17
- # @return [String] description of returned object
18
- def initialize(*dirs)
19
- @memes = {}
20
- load_directory!
21
- dirs.each do |dir|
22
- load_directory!(dir)
23
- end
24
- end
25
-
26
- # Create a meme with the given text
27
- #
28
- # @param path [String] The path to the image file you want to annotate.
29
- # @param top [String] The text you want to appear on the top of the meme.
30
- # @param bottom [String] The text you want to appear on the bottom of the meme.
31
- # @param watermark [String] The watermark text. If nil it is omitted
32
- # @param outpath [String] Where do you want to put the generated meme. Defaults to /tmp/meme-<timestamp>.<extension>
33
- # @param nowrite [Boolean] Returns the meme as a blob (string) instead of writing to disk.
34
- # @return [String] Either the generated meme object (if nowrite) or a path to the meme
35
- def generate(path:, top: nil, bottom: nil, watermark: nil, outpath: nil, nowrite: false)
36
- top = (top || '').upcase
37
- bottom = (bottom || '').upcase
38
-
39
- path = Pathname.new(path).realpath
40
-
41
- canvas = Magick::ImageList.new(path)
42
-
43
- caption_meme(top, Magick::NorthGravity, canvas) unless top.empty?
44
- caption_meme(bottom, Magick::SouthGravity, canvas) unless bottom.empty?
45
-
46
- # Draw the watermark
47
- unless watermark.nil?
48
- watermark_draw = Magick::Draw.new
49
- watermark_draw.annotate(canvas, 0, 0, 0, 0, " #{watermark}") do
50
- self.font = 'Helvetica'
51
- self.fill = 'white'
52
- self.text_antialias(false)
53
- self.font_weight = 100
54
- self.gravity = Magick::SouthEastGravity
55
- self.pointsize = 10
56
- self.undercolor = 'hsla(0,0,0,.5)'
57
- end
58
- end
59
-
60
- output_path = outpath || "/tmp/meme-#{Time.now.to_i}#{path.extname}"
61
- if nowrite
62
- canvas.to_blob
63
- else
64
- canvas.write(output_path)
65
- output_path
66
- end
67
- end
68
- alias_method :meme, :generate
69
3
 
70
- # Create a meme, using the pre-loaded templates.
71
- # If no template is specified, randomly picks one
72
- #
73
- # @param name [String] Name of the template to use. See #memes
74
- # @param top [String] The text you want to appear on the top of the meme.
75
- # @param bottom [String] The text you want to appear on the bottom of the meme.
76
- # @param watermark [String] The watermark text. If nil it is omitted
77
- # @param outpath [String] Where do you want to put the generated meme. Defaults to /tmp/meme-<timestamp>.<extension>
78
- # @param nowrite [Boolean] Returns the meme as a blob (string) instead of writing to disk.
79
- # @return [String] Either the generated meme object (if nowrite) or a path to the meme
80
- def fast_meme(name: nil, top: nil, bottom: nil, watermark: nil, outpath: nil, nowrite: false)
81
- if name.nil?
82
- path = @memes[@memes.keys.sample]
83
- elsif @memes[name].nil?
84
- fail ArgumentError, "#{name} is not a pre-loaded meme"
85
- else
86
- path = @memes[name]
87
- end
88
- generate(path: path, top: top, bottom: bottom, watermark: watermark, outpath: outpath, nowrite: nowrite)
89
- end
90
- alias_method :m, :fast_meme
91
-
92
- private
93
-
94
- # Load all images in a directory as memes.
95
- # Last loaded directory overrides first, if there are name conflicts.
96
- #
97
- # @param directory [String] Directory to scrape.
98
- def load_directory!(directory = nil)
99
- directory = directory.nil? ? "#{File.join(File.dirname(File.expand_path(__FILE__)), '../memes')}/*.jpg" : "#{directory}/*"
100
- paths = Dir.glob(directory).select do |path|
101
- path =~ VALID_IMAGE_EXTENSIONS
102
- end
103
- @memes.merge!(paths.reduce({}) do |images, path|
104
- path = Pathname.new(path).realpath
105
- name = path.split.last.sub(VALID_IMAGE_EXTENSIONS, '').to_s
106
- images.merge(name => path)
107
- end)
108
- end
109
-
110
- # Caption a canvas
111
- #
112
- # @param text [String] The text to put on as a caption
113
- # @param gravity [Grav] RMagick Gravity Constant
114
- # @param canvas [Magick::ImageList] ImageList/Canvas to compose the text onto
115
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
116
- def caption_meme(text, gravity, canvas)
117
- text.gsub!('\\', '\\\\\\')
118
-
119
- # 28 is the biggest pointsize memes dont look like shit on
120
- min_pointsize = 28
121
- max_pointsize = 128
122
- current_pointsize = min_pointsize
123
- current_stroke = current_pointsize / 30.0
124
-
125
- max_width = canvas.columns - 20
126
- max_height = (canvas.rows / 2) - 20
127
-
128
- draw = Magick::Draw.new
129
- draw.font = File.join(File.dirname(File.expand_path(__FILE__)), '..', 'fonts', 'Impact.ttf')
130
- draw.font_weight = Magick::BoldWeight
131
- metrics = nil
132
-
133
- # Non-ragged word-wrap
134
- text = word_wrap(text)
135
-
136
- # Calculate out the largest pointsize that will fit
137
- loop do
138
- draw.pointsize = current_pointsize
139
- last_metrics = metrics
140
- metrics = draw.get_multiline_type_metrics(text)
141
-
142
- if metrics.width + current_stroke > max_width ||
143
- metrics.height + current_stroke > max_height ||
144
- current_pointsize > max_pointsize
145
- if current_pointsize > min_pointsize
146
- current_pointsize -= 1
147
- current_stroke = current_pointsize / 30.0
148
- metrics = last_metrics
149
- end
150
- break
151
- else
152
- current_pointsize += 1
153
- current_stroke = current_pointsize / 30.0
154
- end
155
- end
156
- # rubocop:disable Style/RedundantSelf
157
- draw.annotate(canvas, canvas.columns, canvas.rows - 10, 0, 0, text) do
158
- self.interline_spacing = -(current_pointsize / 5)
159
- self.stroke_antialias(true)
160
- self.stroke = 'black'
161
- self.fill = 'white'
162
- self.gravity = gravity
163
- self.stroke_width = current_stroke
164
- self.pointsize = current_pointsize
165
- end
166
- # rubocop:enable Style/RedundantSelf
167
- end
168
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
4
+ require 'le_meme/version'
5
+ require 'le_meme/meme'
6
+ require 'le_meme/meme_lib'
169
7
 
170
- # Wrap the text to fit on a meme
171
- # This basically uses the wordwrapper library, and then does some calculations to split super-long strings
172
- #
173
- # @param text [String] The text string to word-wrap.
174
- # @param col [Fixnum] The number of "columns" to wrap at
175
- # @return [String] The text, with the
176
- def word_wrap(text, col: 24)
177
- text.strip.gsub(/\n\r/, '\s')
178
- text = WordWrapper::MinimumRaggedness.new(col, text).wrap
179
- text = text.split("\n").map do |line|
180
- line.length > col ? line.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/, "\\1\\3\n").strip : line
181
- end * "\n"
182
- text.strip
183
- end
8
+ module LeMeme
9
+ IMAGE_EXTENSIONS = /\.(jp[e]?g|png|gif)$/i
184
10
  end
@@ -0,0 +1,107 @@
1
+ module LeMeme
2
+ # A single meme object
3
+ class Meme
4
+ attr_accessor(*%i(path top bottom watermark))
5
+ # @param [String, Pathanem] path Path to an image for the meme background
6
+ # @param [String] top: nil The text on the top of the meme
7
+ # @param [String] bottom: nil The text on the bottom of the meme
8
+ # @param [String] watermark: nil Watermark text
9
+ # @return [Meme] A new meme object
10
+ def initialize(path, top: nil, bottom: nil, watermark: nil)
11
+ @path = File.expand_path(path)
12
+ @top = top.to_s.upcase
13
+ @bottom = bottom.to_s.upcase
14
+ @watermark = watermark
15
+ @canvas = Magick::ImageList.new(@path)
16
+ end
17
+
18
+ # Outputs the meme to the file system
19
+ #
20
+ # @param [String] path = nil Where to save the meme
21
+ # @return [File] File object representing the meme
22
+ def to_file(path = nil)
23
+ path = File.expand_path(path.nil? ? "#{ENV['TMPDIR']}meme-#{Time.now.to_i}.jpg" : path)
24
+ generate!
25
+
26
+ file = File.new(path, 'w+')
27
+ @canvas.write(path)
28
+
29
+ file
30
+ end
31
+
32
+ # Get a binary string representing the meme
33
+ #
34
+ # @return [String]
35
+ def to_blob
36
+ generate!
37
+
38
+ @canvas.to_blob
39
+ end
40
+
41
+ private
42
+
43
+ def generate!
44
+ return if @generated
45
+ @generated = true
46
+ caption(@top, Magick::NorthGravity) unless @top.empty?
47
+ caption(@bottom, Magick::SouthGravity) unless @bottom.empty?
48
+ watermark unless watermark.nil?
49
+ end
50
+
51
+ # rubocop:disable Metrics/MethodLength
52
+ def caption(text, gravity)
53
+ text = word_wrap(text)
54
+ draw, pointsize = calculate_pointsize(text)
55
+
56
+ draw.annotate(@canvas, @canvas.columns, @canvas.rows - 10, 0, 0, text) do
57
+ self.interline_spacing = -(pointsize / 5)
58
+ stroke_antialias(true)
59
+ self.stroke = 'black'
60
+ self.fill = 'white'
61
+ self.gravity = gravity
62
+ self.stroke_width = pointsize / 30.0
63
+ self.pointsize = pointsize
64
+ end
65
+ end
66
+ # rubocop:enable Metrics/MethodLength
67
+
68
+ def watermark
69
+ draw = Magick::Draw.new
70
+ draw.annotate(@canvas, 0, 0, 0, 0, " #{@watermark}") do
71
+ self.fill = 'white'
72
+ text_antialias(false)
73
+ self.font_weight = 100
74
+ self.gravity = Magick::SouthEastGravity
75
+ self.pointsize = 10
76
+ self.undercolor = 'hsla(0,0,0,.5)'
77
+ end
78
+ end
79
+
80
+ # rubocop:disable Metrics/AbcSize
81
+ def calculate_pointsize(text, size_range: 28...128)
82
+ draw = Magick::Draw.new
83
+ draw.font = File.join(File.dirname(File.expand_path(__FILE__)), '..', '..', 'fonts', 'Impact.ttf')
84
+ draw.font_weight = Magick::BoldWeight
85
+
86
+ size = size_range.detect(-> { size_range.last }) do |pointsize|
87
+ draw.pointsize = pointsize + 1
88
+ current_stroke = pointsize / 30.0
89
+
90
+ metrics = draw.get_multiline_type_metrics(text)
91
+
92
+ metrics.width + current_stroke > @canvas.columns - 20 || metrics.height + current_stroke > (@canvas.rows / 2) - 20
93
+ end
94
+ [draw, size]
95
+ end
96
+ # rubocop:enable Metrics/AbcSize
97
+
98
+ def word_wrap(text, col: 24)
99
+ text.strip.gsub(/\n\r/, '\s')
100
+ text = WordWrapper::MinimumRaggedness.new(col, text).wrap
101
+ text = text.split("\n").map do |line|
102
+ line.length > col ? line.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/, "\\1\\3\n").strip : line
103
+ end * "\n"
104
+ text.strip
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,49 @@
1
+ module LeMeme
2
+ # Utility for easily generating memes based off templates
3
+ class MemeLib
4
+ attr_reader :memes
5
+ # Creates a meme library
6
+ #
7
+ # @param [String] *dirs Directory glob patterns to meme templates
8
+ # @return [MemeLib]
9
+ def initialize(*dirs)
10
+ @memes = {}
11
+ dirs.each(&method(:load_directory!))
12
+ end
13
+
14
+ # Creates a meme library, preloaded with the included templates
15
+ #
16
+ # @return [MemeLib]
17
+ def self.new_with_default_memes
18
+ path = File.join(File.dirname(File.expand_path(__FILE__)), '..', '..', 'memes', '*')
19
+ new(path)
20
+ end
21
+
22
+ # Loads a directory into the MemeLib, for template consumption
23
+ # Clobbers any existing templates
24
+ #
25
+ # @param [String] dir Directory glob pattern to meme templates
26
+ # @return [Hash] Hash of all templates and their filepaths
27
+ def load_directory!(dir)
28
+ paths = Dir.glob(dir).grep LeMeme::IMAGE_EXTENSIONS
29
+ @memes.merge!(paths.reduce({}) do |images, path|
30
+ path = File.expand_path(path)
31
+ name = path.split.last.sub(LeMeme::IMAGE_EXTENSIONS, '').to_s
32
+ images.merge(name => path)
33
+ end)
34
+ end
35
+
36
+ # Create a meme from a template
37
+ #
38
+ # @param [String] template: nil The template to use. Omit for random template
39
+ # @param [String] top: nil
40
+ # @param [String] bottom: nil
41
+ # @param [String] watermark: nil
42
+ # @return [LeMeme::Meme]
43
+ def meme(template: nil, top: nil, bottom: nil, watermark: nil)
44
+ path = template.nil? ? @memes.values.sample : @memes[template]
45
+
46
+ Meme.new(path, top: top, bottom: bottom, watermark: watermark)
47
+ end
48
+ end
49
+ end
@@ -1,3 +1,4 @@
1
- class LeMeme
2
- VERSION = "0.0.8"
1
+ # frozen_string_literal: true
2
+ module LeMeme
3
+ VERSION = '0.1.0'.freeze
3
4
  end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe LeMeme::Meme do
4
+ subject { LeMeme::Meme.new('memes/maymay.jpg') }
5
+ describe :new do
6
+ context 'without text' do
7
+ it { is_expected.to be_a LeMeme::Meme }
8
+ it { expect(subject.path).to match(%r{memes/maymay.jpg$}) }
9
+ end
10
+
11
+ context 'with text' do
12
+ subject do
13
+ LeMeme::Meme.new('memes/maymay.jpg', top: 'top text', bottom: 'bottom text')
14
+ end
15
+
16
+ it { expect(subject.top).to eql('TOP TEXT') }
17
+ it { expect(subject.bottom).to eql('BOTTOM TEXT') }
18
+ end
19
+ end
20
+
21
+ describe :to_file do
22
+ it { expect(subject.to_file).to be_a(File) }
23
+ it { expect(subject.to_file.path).to match(/#{ENV['TMPDIR']}meme-\d+.jpg/) }
24
+ end
25
+
26
+ describe :to_blob do
27
+ it { expect(subject.to_blob).to be_a(String) }
28
+ it { expect(subject.to_blob.size).to eql(43_685) }
29
+ end
30
+ end
@@ -1,6 +1,4 @@
1
1
  require 'pry'
2
2
  require 'le_meme'
3
3
 
4
- RSpec.configure do |c|
5
- c.raise_errors_for_deprecations!
6
- end
4
+ RSpec.configure(&:raise_errors_for_deprecations!)
metadata CHANGED
@@ -1,131 +1,136 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: le_meme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Sandberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-17 00:00:00.000000000 Z
11
+ date: 2016-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.7'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.7'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '0.10'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '0.10'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rspec
56
+ name: pry-byebug
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '3.1'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '3.1'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rmagick
70
+ name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '2.13'
76
- type: :runtime
75
+ version: '0'
76
+ type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '2.13'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: word_wrapper
84
+ name: rmagick
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 0.5.0
89
+ version: '2.15'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 0.5.0
96
+ version: '2.15'
97
97
  - !ruby/object:Gem::Dependency
98
- name: slop
98
+ name: word_wrapper
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '3.6'
103
+ version: 0.5.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '3.6'
110
+ version: 0.5.0
111
111
  description: A gem that generates memes. Can be used as a library or command-line
112
112
  executable.
113
113
  email:
114
114
  - paradox460@gmail.com
115
115
  executables:
116
+ - console
116
117
  - meme
117
118
  extensions: []
118
119
  extra_rdoc_files: []
119
120
  files:
120
121
  - ".gitignore"
122
+ - ".rubocop.yml"
121
123
  - Gemfile
122
124
  - LICENSE.txt
123
125
  - README.md
124
126
  - Rakefile
127
+ - bin/console
125
128
  - bin/meme
126
129
  - fonts/Impact.ttf
127
130
  - le_meme.gemspec
128
131
  - lib/le_meme.rb
132
+ - lib/le_meme/meme.rb
133
+ - lib/le_meme/meme_lib.rb
129
134
  - lib/le_meme/version.rb
130
135
  - memes/10guy.jpg
131
136
  - memes/aaduck.jpg
@@ -208,7 +213,7 @@ files:
208
213
  - memes/wonka.jpg
209
214
  - memes/yee.jpg
210
215
  - memes/yuno.jpg
211
- - spec/le_meme_spec.rb
216
+ - spec/le_meme/meme_spec.rb
212
217
  - spec/spec_helper.rb
213
218
  homepage: http://github.com/paradox460/le_meme
214
219
  licenses:
@@ -222,7 +227,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
222
227
  requirements:
223
228
  - - ">="
224
229
  - !ruby/object:Gem::Version
225
- version: '0'
230
+ version: '2.1'
226
231
  required_rubygems_version: !ruby/object:Gem::Requirement
227
232
  requirements:
228
233
  - - ">="
@@ -230,10 +235,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
230
235
  version: '0'
231
236
  requirements: []
232
237
  rubyforge_project:
233
- rubygems_version: 2.4.5
238
+ rubygems_version: 2.5.1
234
239
  signing_key:
235
240
  specification_version: 4
236
241
  summary: Dank memes, in gem form
237
242
  test_files:
238
- - spec/le_meme_spec.rb
243
+ - spec/le_meme/meme_spec.rb
239
244
  - spec/spec_helper.rb
@@ -1,68 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe LeMeme do
4
- let(:meme) { LeMeme.new }
5
-
6
- describe '#generate' do
7
- let(:image) { File.join(File.dirname(File.expand_path(__FILE__)), '../memes/maymay.jpg') }
8
- context 'without an image path' do
9
- it 'should raise ArgumentError with "missing keyword: path"' do
10
- expect { meme.generate }.to raise_error(ArgumentError, 'missing keyword: path')
11
- end
12
- end
13
- context 'with an image path' do
14
- x = ['text', nil] * 3
15
- x.permutation(3).to_a.uniq.each do |top, bottom, watermark|
16
- it "should generate a meme with top: '#{top}', bottom: '#{bottom}', and watermark: '#{watermark}'" do
17
- expect_any_instance_of(Magick::ImageList).to receive(:write).and_return("/tmp/meme-#{Time.now.to_i}.jpg")
18
- expect(meme.generate(path: image, top: top, bottom: bottom, watermark: watermark)).to match(%r{/tmp/meme-\d+.jpg})
19
- end
20
- end
21
- end
22
- context 'with an outpath' do
23
- it 'should generate a meme at the specified outpath' do
24
- expect_any_instance_of(Magick::ImageList).to receive(:write).and_return('test.jpg')
25
- expect(meme.generate(path: image, top: 'top', bottom: 'bottom', outpath: 'test.jpg')).to eq('test.jpg')
26
- end
27
- end
28
- context 'with nowrite set to true' do
29
- it 'should output the meme as a blob string' do
30
- mymeme = meme.generate(path: image, nowrite: true)
31
- expect(mymeme.size).to eq(43618)
32
- end
33
- end
34
- end
35
-
36
- describe '#meme' do
37
- it 'should be an alias of #generate' do
38
- expect(meme.method(:meme)).to eq(meme.method(:generate))
39
- end
40
- end
41
-
42
- describe '#fast_meme' do
43
- let(:template) { 'maymay' }
44
- it 'should pass its params to generate_meme' do
45
- expect(meme).to receive(:generate) do |args|
46
- expect(args[:path]).to eq(Pathname.new('/Users/jeffsandberg/Developer/le_meme/memes/maymay.jpg'))
47
- expect(args[:top]).to eq('top text')
48
- expect(args[:bottom]).to eq('bottom text')
49
- expect(args[:watermark]).to eq('watermark')
50
- expect(args[:outpath]).to eq('outpath')
51
- end
52
- meme.fast_meme(name: template, top: 'top text', bottom: 'bottom text', watermark: 'watermark', outpath: 'outpath')
53
- end
54
-
55
- context 'without a specified template' do
56
- it 'should generate a meme' do
57
- expect_any_instance_of(Magick::ImageList).to receive(:write).and_return("/tmp/meme-#{Time.now.to_i}.jpg")
58
- expect(meme.fast_meme).to match(%r{/tmp/meme-\d+.jpg})
59
- end
60
- end
61
- end
62
-
63
- describe '#m' do
64
- it 'should be an alias of #fast_meme' do
65
- expect(meme.method(:m)).to eq(meme.method(:fast_meme))
66
- end
67
- end
68
- end