├── .gitignore ├── .rspec ├── CODE_OF_CONDUCT.md ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── lib ├── rails-webp.rb └── rails │ ├── webp.rb │ └── webp │ ├── converter.rb │ ├── post_processor.rb │ ├── railtie.rb │ └── version.rb ├── rails-webp.gemspec └── spec ├── fixtures ├── public │ └── #-this-is-permanent.webp ├── test.jpg └── test.webp ├── rails ├── webp │ ├── converter_spec.rb │ └── version_spec.rb └── webp_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | 10 | # rspec failure tracking 11 | .rspec_status 12 | 13 | .DS_Store 14 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at hello@jakenberg.io. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem's dependencies in rails-webp.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | rails-webp (0.1.2) 5 | mini_magick 6 | rails 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | actioncable (6.1.3.2) 12 | actionpack (= 6.1.3.2) 13 | activesupport (= 6.1.3.2) 14 | nio4r (~> 2.0) 15 | websocket-driver (>= 0.6.1) 16 | actionmailbox (6.1.3.2) 17 | actionpack (= 6.1.3.2) 18 | activejob (= 6.1.3.2) 19 | activerecord (= 6.1.3.2) 20 | activestorage (= 6.1.3.2) 21 | activesupport (= 6.1.3.2) 22 | mail (>= 2.7.1) 23 | actionmailer (6.1.3.2) 24 | actionpack (= 6.1.3.2) 25 | actionview (= 6.1.3.2) 26 | activejob (= 6.1.3.2) 27 | activesupport (= 6.1.3.2) 28 | mail (~> 2.5, >= 2.5.4) 29 | rails-dom-testing (~> 2.0) 30 | actionpack (6.1.3.2) 31 | actionview (= 6.1.3.2) 32 | activesupport (= 6.1.3.2) 33 | rack (~> 2.0, >= 2.0.9) 34 | rack-test (>= 0.6.3) 35 | rails-dom-testing (~> 2.0) 36 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 37 | actiontext (6.1.3.2) 38 | actionpack (= 6.1.3.2) 39 | activerecord (= 6.1.3.2) 40 | activestorage (= 6.1.3.2) 41 | activesupport (= 6.1.3.2) 42 | nokogiri (>= 1.8.5) 43 | actionview (6.1.3.2) 44 | activesupport (= 6.1.3.2) 45 | builder (~> 3.1) 46 | erubi (~> 1.4) 47 | rails-dom-testing (~> 2.0) 48 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 49 | activejob (6.1.3.2) 50 | activesupport (= 6.1.3.2) 51 | globalid (>= 0.3.6) 52 | activemodel (6.1.3.2) 53 | activesupport (= 6.1.3.2) 54 | activerecord (6.1.3.2) 55 | activemodel (= 6.1.3.2) 56 | activesupport (= 6.1.3.2) 57 | activestorage (6.1.3.2) 58 | actionpack (= 6.1.3.2) 59 | activejob (= 6.1.3.2) 60 | activerecord (= 6.1.3.2) 61 | activesupport (= 6.1.3.2) 62 | marcel (~> 1.0.0) 63 | mini_mime (~> 1.0.2) 64 | activesupport (6.1.3.2) 65 | concurrent-ruby (~> 1.0, >= 1.0.2) 66 | i18n (>= 1.6, < 2) 67 | minitest (>= 5.1) 68 | tzinfo (~> 2.0) 69 | zeitwerk (~> 2.3) 70 | builder (3.2.4) 71 | concurrent-ruby (1.1.8) 72 | crass (1.0.6) 73 | diff-lcs (1.4.4) 74 | erubi (1.10.0) 75 | globalid (0.4.2) 76 | activesupport (>= 4.2.0) 77 | i18n (1.8.10) 78 | concurrent-ruby (~> 1.0) 79 | loofah (2.9.1) 80 | crass (~> 1.0.2) 81 | nokogiri (>= 1.5.9) 82 | mail (2.7.1) 83 | mini_mime (>= 0.1.1) 84 | marcel (1.0.1) 85 | method_source (1.0.0) 86 | mini_magick (4.11.0) 87 | mini_mime (1.0.3) 88 | mini_portile2 (2.5.1) 89 | minitest (5.14.4) 90 | nio4r (2.5.7) 91 | nokogiri (1.11.3) 92 | mini_portile2 (~> 2.5.0) 93 | racc (~> 1.4) 94 | racc (1.5.2) 95 | rack (2.2.3) 96 | rack-test (1.1.0) 97 | rack (>= 1.0, < 3) 98 | rails (6.1.3.2) 99 | actioncable (= 6.1.3.2) 100 | actionmailbox (= 6.1.3.2) 101 | actionmailer (= 6.1.3.2) 102 | actionpack (= 6.1.3.2) 103 | actiontext (= 6.1.3.2) 104 | actionview (= 6.1.3.2) 105 | activejob (= 6.1.3.2) 106 | activemodel (= 6.1.3.2) 107 | activerecord (= 6.1.3.2) 108 | activestorage (= 6.1.3.2) 109 | activesupport (= 6.1.3.2) 110 | bundler (>= 1.15.0) 111 | railties (= 6.1.3.2) 112 | sprockets-rails (>= 2.0.0) 113 | rails-dom-testing (2.0.3) 114 | activesupport (>= 4.2.0) 115 | nokogiri (>= 1.6) 116 | rails-html-sanitizer (1.3.0) 117 | loofah (~> 2.3) 118 | railties (6.1.3.2) 119 | actionpack (= 6.1.3.2) 120 | activesupport (= 6.1.3.2) 121 | method_source 122 | rake (>= 0.8.7) 123 | thor (~> 1.0) 124 | rake (13.0.3) 125 | rspec (3.10.0) 126 | rspec-core (~> 3.10.0) 127 | rspec-expectations (~> 3.10.0) 128 | rspec-mocks (~> 3.10.0) 129 | rspec-core (3.10.1) 130 | rspec-support (~> 3.10.0) 131 | rspec-expectations (3.10.1) 132 | diff-lcs (>= 1.2.0, < 2.0) 133 | rspec-support (~> 3.10.0) 134 | rspec-mocks (3.10.2) 135 | diff-lcs (>= 1.2.0, < 2.0) 136 | rspec-support (~> 3.10.0) 137 | rspec-support (3.10.2) 138 | sprockets (4.0.2) 139 | concurrent-ruby (~> 1.0) 140 | rack (> 1, < 3) 141 | sprockets-rails (3.2.2) 142 | actionpack (>= 4.0) 143 | activesupport (>= 4.0) 144 | sprockets (>= 3.0.0) 145 | thor (1.1.0) 146 | tzinfo (2.0.4) 147 | concurrent-ruby (~> 1.0) 148 | websocket-driver (0.7.3) 149 | websocket-extensions (>= 0.1.0) 150 | websocket-extensions (0.1.5) 151 | zeitwerk (2.4.2) 152 | 153 | PLATFORMS 154 | ruby 155 | 156 | DEPENDENCIES 157 | bundler (~> 2.0) 158 | rails-webp! 159 | rake (~> 13.0) 160 | rspec (~> 3.0) 161 | 162 | BUNDLED WITH 163 | 2.0.1 164 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Jake Peterson 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rails::Webp 2 | 3 | Create webp copies of your image assets the easy way using [minimagick](https://github.com/minimagick/minimagick)! 4 | 5 | ## Installation 6 | 7 | Before installing, make sure you have [ImageMagick](https://imagemagick.org/script/download.php) installed on your host. 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | ```ruby 12 | gem 'rails-webp' 13 | ``` 14 | 15 | And then execute: 16 | 17 | $ bundle 18 | 19 | Or install it yourself as: 20 | 21 | $ gem install rails-webp 22 | 23 | ## Usage 24 | 25 | This gem is intended to be used as a post processor step in your asset pipeline: 26 | ``` 27 | bundle exec rake assets:precompile 28 | ``` 29 | 30 | You can configure options passed to ImageMagick in an initializer: 31 | 32 | `config/initializers/webp.rb`: 33 | 34 | ``` 35 | Rails::WebP.encode_options = { quality: 80, lossless: true, method: 6, alpha_filtering: 2, alpha_compression: 0, alpha_quality: 100 } 36 | ``` 37 | 38 | A comprehensive list of options can be found [here](https://imagemagick.org/script/webp.php). 39 | 40 | **Note:** a digest is included in the processed webp image's file name. This digest is compared for each time compilation occurs. 41 | By default, `rails-webp` will only process images that have a mismatched digest (AKA hash of source image contents). 42 | If you wish to force webp processing: 43 | 44 | ``` 45 | Rails::WebP.force = true # default: false 46 | ``` 47 | 48 | 49 | ## Motivations for this gem 50 | 51 | In my experience, the existing gems for processing webp images in the Rails Asset Pipeline made questionable assumptions. 52 | More importantly, I could not use the native libraries used by those gems in my team's acceptance/production environment. 53 | ImageMagick was an easy choice for this reason because it's widely implemented, used, and understood (my opinion). 54 | 55 | ## Development 56 | 57 | After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 58 | 59 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 60 | 61 | ## Contributing 62 | 63 | Bug reports and pull requests are welcome on GitHub at https://github.com/jakenberg/rails-webp. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 64 | 65 | ## License 66 | 67 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 68 | 69 | ## Code of Conduct 70 | 71 | Everyone interacting in the Rails::Webp project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/jakenberg/rails-webp/blob/master/CODE_OF_CONDUCT.md). 72 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "rails/webp" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /lib/rails-webp.rb: -------------------------------------------------------------------------------- 1 | require 'rails/webp' 2 | -------------------------------------------------------------------------------- /lib/rails/webp.rb: -------------------------------------------------------------------------------- 1 | require "rails/webp/version" 2 | 3 | require 'rails/webp/converter' 4 | require 'rails/webp/post_processor' 5 | require 'rails/webp/railtie' 6 | 7 | module Rails 8 | module WebP 9 | class Error < StandardError; end 10 | 11 | class << self 12 | attr_writer :encode_options, :exclude_dir_regex, :force 13 | 14 | def encode_options 15 | @encode_options ||= { quality: 80, lossless: true, method: 6, alpha_filtering: 2, alpha_compression: 0, alpha_quality: 100 } 16 | end 17 | 18 | def exclude_dir_regex 19 | @exclude_dir_regex ||= nil 20 | end 21 | 22 | # Source assets that are unchanged will not be processed by default. 23 | # Set this to true if you wish to process webp images anyway. 24 | def force 25 | @force ||= false 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/rails/webp/converter.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | require 'logger' 3 | require 'mini_magick' 4 | 5 | module Rails 6 | module WebP 7 | class Converter 8 | class << self 9 | attr_reader :context 10 | 11 | def convert_to_webp(input_path, output_path) 12 | # Ex: convert wizard.png -quality 50 -define webp:lossless=true wizard.webp 13 | MiniMagick::Tool::Convert.new do |convert| 14 | convert << input_path 15 | options = WebP.encode_options 16 | convert << '-quality' << options[:quality] 17 | options.except(:quality).each do |name, value| 18 | convert << "-define" << "webp:#{name.to_s.dasherize}=#{value}" 19 | end 20 | convert << output_path 21 | end 22 | end 23 | 24 | def process(input_path, data, context, app = Rails.application) 25 | return data if excluded_dir?(input_path) 26 | @context = context 27 | prefix = app.config.assets.prefix 28 | digest = data_digest(data) 29 | webp_file = webp_file_name(data, digest) 30 | output_path = Pathname.new(File.join(app.root, 'public', prefix, webp_file)) 31 | if WebP.force || !webp_file_exists?(digest, output_path) 32 | FileUtils.mkdir_p(output_path.dirname) unless Dir.exists?(output_path.dirname) 33 | # TODO: check app.assets.gzip and act accordingly 34 | convert_to_webp(input_path, output_path) 35 | logger&.info "Writing #{output_path}" 36 | end 37 | data 38 | end 39 | 40 | private 41 | 42 | def data_digest(data) 43 | "-#{context.environment.digest_class.new.update(data).to_s}" 44 | end 45 | 46 | def excluded_dir?(path) 47 | regex = WebP.exclude_dir_regex 48 | return false unless regex 49 | !!path.match(regex) 50 | end 51 | 52 | def webp_file_name(data, digest) 53 | file_name = context.logical_path # Original File name w/o extension 54 | file_ext = File.extname(context.filename) # Original File extension 55 | "#{file_name}#{digest}.webp" # WebP File fullname 56 | end 57 | 58 | def webp_file_exists?(digest, output_path) 59 | File.exists?(output_path) && digest == output_path.to_s.split('-').last.split('.').first 60 | end 61 | 62 | def logger 63 | if context && context.environment 64 | context.environment.logger 65 | else 66 | logger = Logger.new($stderr) 67 | logger.level = Logger::FATAL 68 | logger 69 | end 70 | end 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/rails/webp/post_processor.rb: -------------------------------------------------------------------------------- 1 | module Rails 2 | module WebP 3 | class PostProcessor 4 | def initialize(filename, &block) 5 | @filename = filename 6 | @source = block.call 7 | end 8 | 9 | def render(context, empty_hash_wtf) 10 | self.class.run(@filename, @source, context) 11 | end 12 | 13 | def self.run(filename, data, context) 14 | Converter.process(filename, data, context) 15 | end 16 | 17 | def self.call(input) 18 | filename = input[:filename] 19 | source = input[:data] 20 | context = input[:environment].context_class.new(input) 21 | 22 | result = run(filename, source, context) 23 | context.metadata.merge(data: result) 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/rails/webp/railtie.rb: -------------------------------------------------------------------------------- 1 | require 'sprockets/processing' 2 | 3 | module Rails 4 | module WebP 5 | class Railtie < ::Rails::Railtie 6 | extend Sprockets::Processing 7 | 8 | initializer :webp, group: :all do |app| 9 | app.config.assets.configure do |env| 10 | env.register_mime_type 'image/jpeg', extensions: ['.jpeg'] 11 | env.register_postprocessor 'image/jpeg', PostProcessor 12 | 13 | env.register_mime_type 'image/png', extensions: ['.png'] 14 | env.register_postprocessor 'image/png', PostProcessor 15 | end 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/rails/webp/version.rb: -------------------------------------------------------------------------------- 1 | module Rails 2 | module WebP 3 | VERSION = "0.1.3" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /rails-webp.gemspec: -------------------------------------------------------------------------------- 1 | 2 | lib = File.expand_path("../lib", __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require "rails/webp/version" 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "rails-webp" 8 | spec.version = Rails::WebP::VERSION 9 | spec.authors = ["Jake Peterson"] 10 | spec.email = ["hello@jakenberg.io"] 11 | 12 | spec.summary = %q{Use minimagick during asset precompilation to make a copy of jpg/png as webp} 13 | spec.description = %q{I have a dream, that one day, Rails won't make us write descriptions before our gems compile.} 14 | spec.homepage = "https://github.com/jakenberg" 15 | spec.license = "MIT" 16 | 17 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' 18 | # to allow pushing to a single host or delete this section to allow pushing to any host. 19 | if spec.respond_to?(:metadata) 20 | spec.metadata["allowed_push_host"] = "https://rubygems.org" 21 | 22 | spec.metadata["homepage_uri"] = spec.homepage 23 | spec.metadata["source_code_uri"] = "https://github.com/jakenberg/rails-webp" 24 | spec.metadata["changelog_uri"] = "https://github.com/jakenberg/rails-webp/CHANGELOG.md" 25 | else 26 | raise "RubyGems 2.0 or newer is required to protect against " \ 27 | "public gem pushes." 28 | end 29 | 30 | # Specify which files should be added to the gem when it is released. 31 | # The `git ls-files -z` loads the files in the RubyGem that have been added into git. 32 | spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do 33 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 34 | end 35 | spec.bindir = "exe" 36 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 37 | spec.require_paths = ["lib"] 38 | 39 | spec.add_development_dependency "bundler", "~> 2.0" 40 | spec.add_development_dependency "rake", "~> 13.0" 41 | spec.add_development_dependency "rspec", "~> 3.0" 42 | 43 | spec.add_dependency "rails" 44 | spec.add_dependency "mini_magick" 45 | end 46 | -------------------------------------------------------------------------------- /spec/fixtures/public/#-this-is-permanent.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xjmp/rails-webp/f248d8cd746878e818a585223345cd368c092a4a/spec/fixtures/public/#-this-is-permanent.webp -------------------------------------------------------------------------------- /spec/fixtures/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xjmp/rails-webp/f248d8cd746878e818a585223345cd368c092a4a/spec/fixtures/test.jpg -------------------------------------------------------------------------------- /spec/fixtures/test.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xjmp/rails-webp/f248d8cd746878e818a585223345cd368c092a4a/spec/fixtures/test.webp -------------------------------------------------------------------------------- /spec/rails/webp/converter_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Rails::WebP::Converter do 4 | let(:input_path) { File.join('spec', 'fixtures', 'test.jpg') } 5 | 6 | before do 7 | File.delete(output_path) if File.exists?(output_path) 8 | # Dir.delete(File.join('spec/fixtures/public')) 9 | end 10 | 11 | describe '#convert_to_webp' do 12 | let(:output_path) { File.join('spec', 'fixtures', 'test.webp') } 13 | 14 | subject { described_class.convert_to_webp(input_path, output_path) } 15 | 16 | it { is_expected_block.to change { File.exists?(output_path) }.from(false).to(true) } 17 | end 18 | 19 | describe '#process' do 20 | let(:application) do 21 | OpenStruct.new( 22 | config: OpenStruct.new( 23 | assets: OpenStruct.new( 24 | prefix: '', 25 | ), 26 | ), 27 | root: 'spec/fixtures/', 28 | ) 29 | end 30 | let(:context) do 31 | class DummyDigestClass 32 | def update(_) 33 | 'this-is-permanent' 34 | end 35 | end 36 | OpenStruct.new( 37 | environment: OpenStruct.new( 38 | digest_class: DummyDigestClass, 39 | ), 40 | logical_path: 'test', 41 | pathname: OpenStruct.new( 42 | extname: 'webp', 43 | ), 44 | ) 45 | end 46 | let(:data) { File.read(input_path) } 47 | let(:output_path) { File.join('spec', 'fixtures', 'public', 'test-this-is-permanent.webp') } 48 | 49 | subject { described_class.process(input_path, data, context, application) } 50 | 51 | it { is_expected_block.to change { File.exists?(output_path) }.from(false).to(true) } 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/rails/webp/version_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Rails::WebP do 4 | subject { described_class::VERSION } 5 | 6 | it { is_expected.not_to be_nil } 7 | end 8 | -------------------------------------------------------------------------------- /spec/rails/webp_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Rails::WebP do 4 | describe '#encode_options' do 5 | subject { described_class.encode_options } 6 | 7 | it { is_expected.not_to be_nil } 8 | end 9 | 10 | describe '#force' do 11 | subject { described_class.force } 12 | 13 | it { is_expected.not_to be_nil } 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | require 'rails/railtie' 3 | require "rails/webp" 4 | 5 | module RSpecHelpers 6 | def is_expected_block 7 | expect { subject } 8 | end 9 | end 10 | 11 | RSpec.configure do |config| 12 | # Enable flags like --only-failures and --next-failure 13 | config.example_status_persistence_file_path = ".rspec_status" 14 | 15 | # Disable RSpec exposing methods globally on `Module` and `main` 16 | config.disable_monkey_patching! 17 | 18 | config.expect_with :rspec do |c| 19 | c.syntax = :expect 20 | end 21 | 22 | config.include RSpecHelpers 23 | end 24 | --------------------------------------------------------------------------------