diff --git a/.gitignore b/.gitignore index fa77609..c72a77e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.gem *.ordinare +/coverage diff --git a/README.md b/README.md index 1534bbf..1da4d33 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://semaphoreci.com/api/v1/nikolalsvk/ordinare/branches/master/shields_badge.svg)](https://semaphoreci.com/nikolalsvk/ordinare) [![Gem Version](https://badge.fury.io/rb/ordinare.svg)](https://badge.fury.io/rb/ordinare) +[![codecov](https://codecov.io/gh/nikolalsvk/ordinare/branch/master/graph/badge.svg)](https://codecov.io/gh/nikolalsvk/ordinare) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md#5-make-a-pull-request) Ordinare sorts gems in your Gemfile alphabetically diff --git a/bin/ordinare b/bin/ordinare index a90f276..8538f42 100755 --- a/bin/ordinare +++ b/bin/ordinare @@ -5,5 +5,5 @@ require "ordinare" if ARGV.size > 0 Ordinare.parse_args else - Ordinare.sort + Ordinare::Sort.sort_gemfile end diff --git a/lib/ordinare.rb b/lib/ordinare.rb index 417fdc1..fbd977f 100644 --- a/lib/ordinare.rb +++ b/lib/ordinare.rb @@ -1,4 +1,6 @@ require "ordinare/version" +require "ordinare/sort" +require "ordinare/check" require "optparse" module Ordinare @@ -13,6 +15,7 @@ def parse_args overwrite = true version = nil help = nil + check = nil OptionParser.new do |opts| opts.banner = "Usage: ordinare inside your Rails project" @@ -27,6 +30,10 @@ def parse_args overwrite = false end + opts.on("-c", "--check", "Check if Gemfile is sorted properly") do + check = true + end + opts.on("-v", "--version", "Check gem version") do puts Ordinare::VERSION version = true @@ -38,64 +45,13 @@ def parse_args end end.parse! - Ordinare.sort(overwrite, path) unless version || help - end - - def sort(overwrite = true, path = "Gemfile") - unless File.file?(path) - abort("No Gemfile found in the current directory, is this a Rails project with Gemfile?") - end - - content = File.readlines(path) + return if version || help - ranges_to_sort = find_ranges_of_gems(content) - - ranges_to_sort.each do |range| - content[range[:start_index]..range[:end_index]] = - content[range[:start_index]..range[:end_index]].sort - end - - path = "#{path}.ordinare" unless overwrite - - File.open(path, "w+") do |file| - content.each { |line| file.puts(line) } - end - - puts "Your sorted Gemfile can be found at #{path} path" - end - - def find_ranges_of_gems(content) - gems = content.each_with_index.map do |line, index| - if line.strip.start_with?("gem ") - index - end - end - - ranges_to_sort = [] - gems.each_with_index do |gem, index| - current_range = if ranges_to_sort.last && !ranges_to_sort.last[:end_index] - ranges_to_sort.last - else - { :start_index => nil, :end_index => nil } - end - start_index = current_range[:start_index] - end_index = current_range[:end_index] - - if gem && !gems[index - 1] && gems[index + 1] - current_range[:start_index] = index - current_range[:end_index] = index if index == gems.length - 1 - - ranges_to_sort << current_range unless ranges_to_sort.any? { |range| range[:start_index] == index } - elsif gem && gems[index - 1] && !gems[index + 1] - ranges_to_sort.map do |range| - if range[:start_index] == start_index - range[:end_index] = index - end - - range - end - end + if check + Ordinare::Check.gemfile_sorted?(path) + else + puts path + Ordinare::Sort.sort_gemfile(overwrite, path) end - ranges_to_sort end end diff --git a/lib/ordinare/check.rb b/lib/ordinare/check.rb new file mode 100644 index 0000000..f06ea15 --- /dev/null +++ b/lib/ordinare/check.rb @@ -0,0 +1,28 @@ +module Ordinare + class Check + def self.gemfile_sorted?(path = "Gemfile") + new(path).gemfile_sorted? + end + + def initialize(path) + @path = path + end + + def gemfile_sorted? + unless File.file?(@path) + abort "No Gemfile found in the current directory, is this a Rails project with Gemfile?" + end + + ordered_content = Ordinare::Sort.sort_content(@path, File.readlines(@path)) + + read_content = File.readlines(@path) + + if read_content == ordered_content + puts "Gemfile is sorted properly" + true + else + abort "Gemfile is not sorted" + end + end + end +end diff --git a/lib/ordinare/sort.rb b/lib/ordinare/sort.rb new file mode 100644 index 0000000..da63c80 --- /dev/null +++ b/lib/ordinare/sort.rb @@ -0,0 +1,85 @@ +module Ordinare + class Sort + def self.sort_gemfile(overwrite = true, path = "Gemfile") + new(overwrite, path).sort_gemfile + end + + def self.sort_content(path = "Gemfile", content) + new(false, path).sort_content(content) + end + + def initialize(overwrite, path) + @overwrite = overwrite + @read_path = path + @write_path = overwrite ? @read_path : "#{path}.ordinare" + end + + def sort_gemfile + unless File.file?(@read_path) + abort "No Gemfile found in the current directory, is this a Rails project with Gemfile?" + end + + read_content = File.readlines(@read_path) + + ordered_content = sort_content(read_content) + + write_to_a_file(ordered_content) + end + + def sort_content(content) + ranges_to_sort = find_ranges_of_gems(content) + + ranges_to_sort.each do |range| + content[range[:start_index]..range[:end_index]] = + content[range[:start_index]..range[:end_index]].sort + end + + content + end + + private + + def find_ranges_of_gems(content) + gems = content.each_with_index.map do |line, index| + if line.strip.start_with?("gem ") + index + end + end + + ranges_to_sort = [] + gems.each_with_index do |gem, index| + current_range = if ranges_to_sort.last && !ranges_to_sort.last[:end_index] + ranges_to_sort.last + else + { :start_index => nil, :end_index => nil } + end + start_index = current_range[:start_index] + end_index = current_range[:end_index] + + if gem && !gems[index - 1] && gems[index + 1] + current_range[:start_index] = index + current_range[:end_index] = index if index == gems.length - 1 + + ranges_to_sort << current_range unless ranges_to_sort.any? { |range| range[:start_index] == index } + elsif gem && gems[index - 1] && !gems[index + 1] + ranges_to_sort.map do |range| + if range[:start_index] == start_index + range[:end_index] = index + end + + range + end + end + end + ranges_to_sort + end + + def write_to_a_file(content) + File.open(@write_path, "w+") do |file| + content.each { |line| file.puts(line) } + end + + puts "Your sorted Gemfile can be found at #{@write_path} path" + end + end +end diff --git a/lib/ordinare/version.rb b/lib/ordinare/version.rb index 7e4f32f..a4502af 100644 --- a/lib/ordinare/version.rb +++ b/lib/ordinare/version.rb @@ -1,3 +1,3 @@ module Ordinare - VERSION = "0.3.0" + VERSION = "0.4.0" end diff --git a/spec/fixtures/ordered_gemfile/Gemfile b/spec/fixtures/ordered_gemfile/Gemfile new file mode 100644 index 0000000..5ffbfd0 --- /dev/null +++ b/spec/fixtures/ordered_gemfile/Gemfile @@ -0,0 +1,60 @@ +source 'http://rubygems.org' + +ruby '2.3.1' + +gem 'rails', '4.2.7.1' + +gem 'coffee-rails', "~> 4.0.1" +gem 'uglifier', "~> 2.7.2" + +gem 'compass-rails', '~> 2.0' +gem 'sass-rails', '~> 4.0.0' + +group :test do + gem "rspec-rails", "~>3.0" + gem 'capybara', '~> 2.6.2' + + gem 'cucumber-rails', '~> 1.4.0', require: false # require: false is needed for cucumber-rails + + gem 'selenium-webdriver', '~> 2.45' + + # Launchy is needed by Capybara, e.g. save_and_open command needs Launchy to open a browser + gem 'connection_pool', "~> 2.1" + gem 'database_cleaner', '~> 1.1' + gem 'email_spec', '~> 1.6.0' + gem 'launchy', '~> 2.4', '>= 2.4.3' + gem 'rack-test', "~> 0.6.2" + gem 'timecop', '~> 0.6.3' + + # required for CircleCI automatic test balancing + gem 'rspec_junit_formatter' +end + +group :development, :test do + gem 'pry-byebug' +end + +gem 'js-routes', '~> 1.2.5' +gem 'therubyracer', '~> 0.12.2', platforms: :ruby + +# Color utilities needed for landing page +gem 'color', '~> 1.8' + +gem 'transit-ruby', '~> 0.8' +gem 'uuidtools', '~> 2.1' + +# Markdown parser +gem 'redcarpet', '~> 3.3', '>= 3.3.4' + +gem 'twilio-ruby', '~> 4.11.1' + +gem 'intercom', '~> 3.5.10' + +gem 'simple_token_authentication', '~> 1.0' + +gem 'daemons' + +gem "select2-rails" + +gem 'client_side_validations' + diff --git a/spec/ordinare/check_spec.rb b/spec/ordinare/check_spec.rb new file mode 100644 index 0000000..ea3e919 --- /dev/null +++ b/spec/ordinare/check_spec.rb @@ -0,0 +1,29 @@ +require "spec_helper" + +describe Ordinare::Check do + describe "#gemfile_sorted?" do + context "no Gemfile found" do + it "aborts with message" do + expect { + described_class.gemfile_sorted?("spec/fixtures/no_gemfile") + }.to raise_error(SystemExit) + end + end + + context "Gemfile is sorted properly" do + it "returns true" do + gemfile_sorted = described_class.gemfile_sorted?("spec/fixtures/ordered_gemfile/Gemfile") + + expect(gemfile_sorted).to be_truthy + end + end + + context "Gemfile is not sorted properly" do + it "raises an exception" do + expect { + described_class.gemfile_sorted?("spec/fixtures/complex_gemfile/Gemfile") + }.to raise_error(SystemExit) + end + end + end +end diff --git a/spec/ordinare/sort_spec.rb b/spec/ordinare/sort_spec.rb new file mode 100644 index 0000000..5e7ede2 --- /dev/null +++ b/spec/ordinare/sort_spec.rb @@ -0,0 +1,40 @@ +require "spec_helper" +require "fileutils" + +describe Ordinare::Sort do + describe "#sort_gemfile" do + context "no Gemfile found" do + it "aborts with message" do + expect { + Ordinare::Sort.sort_gemfile(false, "spec/fixtures/no_gemfile") + }.to raise_error(SystemExit) + end + end + + context "Gemfile found" do + it "sorts basic Gemfile" do + basic_gemfile = "spec/fixtures/basic_gemfile/Gemfile" + Ordinare::Sort.sort_gemfile(false, basic_gemfile) + + same_files = FileUtils.identical?("#{basic_gemfile}.ordered", "#{basic_gemfile}.ordinare") + expect(same_files).to be_truthy + end + + it "sorts Gemfile with groups" do + group_gemfile = "spec/fixtures/group_gemfile/Gemfile" + Ordinare::Sort.sort_gemfile(false, group_gemfile) + + same_files = FileUtils.identical?("#{group_gemfile}.ordered", "#{group_gemfile}.ordinare") + expect(same_files).to be_truthy + end + + it "sorts complicated Gemfile" do + complex_gemfile = "spec/fixtures/complex_gemfile/Gemfile" + Ordinare::Sort.sort_gemfile(false, complex_gemfile) + + same_files = FileUtils.identical?("#{complex_gemfile}.ordered", "#{complex_gemfile}.ordinare") + expect(same_files).to be_truthy + end + end + end +end diff --git a/spec/ordinare_spec.rb b/spec/ordinare_spec.rb index 00e693b..47f9811 100644 --- a/spec/ordinare_spec.rb +++ b/spec/ordinare_spec.rb @@ -1,43 +1,146 @@ require "spec_helper" -require "fileutils" describe Ordinare do - describe "hi" do + describe "#hi" do it "says hi in italian" do expect(Ordinare.hi).to eq "Ciao, sono Ordinare" end end - describe "sort" do - context "no Gemfile found" do - it "aborts with message" do - expect { Ordinare.sort(false, "spec/fixtures/no_gemfile") }.to raise_error(SystemExit) + describe "#parse_args" do + context "path to Gemfile is passed" do + context "using -p" do + before { ARGV = ["-p spec/fixtures/Gemfile"] } + + it "calls sort_gemfile" do + expect(Ordinare::Sort).to receive(:sort_gemfile).with(true, " spec/fixtures/Gemfile") + + Ordinare.parse_args + end + end + + context "using --path" do + before do + ARGV = ["--path=spec/fixtures/Gemfile"] + end + + it "calls sort_gemfile" do + expect(Ordinare::Sort).to receive(:sort_gemfile).with(true, "spec/fixtures/Gemfile") + + Ordinare.parse_args + end + end + end + + context "no overwrite option is passed" do + context "using -n" do + before { ARGV = ["-n"] } + + it "calls sort_gemfile" do + expect(Ordinare::Sort).to receive(:sort_gemfile).with(false, "Gemfile") + + Ordinare.parse_args + end + end + + context "using --no-overwrite" do + before { ARGV = ["--no-overwrite"] } + + it "calls sort_gemfile" do + expect(Ordinare::Sort).to receive(:sort_gemfile).with(false, "Gemfile") + + Ordinare.parse_args + end + end + end + + context "check if Gemfile is sorted properly" do + context "using -c" do + before { ARGV = ["-c"] } + + it "calls gemfile_sorted?" do + expect(Ordinare::Check).to receive(:gemfile_sorted?).with("Gemfile") + + Ordinare.parse_args + end + end + + context "using --check" do + before { ARGV = ["--check"] } + + it "calls gemfile_sorted?" do + expect(Ordinare::Check).to receive(:gemfile_sorted?).with("Gemfile") + + Ordinare.parse_args + end end end - context "Gemfile found" do - it "sorts basic Gemfile" do - basic_gemfile = "spec/fixtures/basic_gemfile/Gemfile" - Ordinare.sort(false, basic_gemfile) + context "get Ordinare version" do + context "using -v" do + before { ARGV = ["-v"] } + + it "doesn't call gemfile_sorted" do + expect(Ordinare::Check).not_to receive(:gemfile_sorted?) + + Ordinare.parse_args + end + + it "doesn't call sort_gemfile" do + expect(Ordinare::Sort).not_to receive(:sort_gemfile) + + Ordinare.parse_args + end + end + + context "using --version" do + before { ARGV = ["--version"] } - same_files = FileUtils.identical?("#{basic_gemfile}.ordered", "#{basic_gemfile}.ordinare") - expect(same_files).to be_truthy + it "doesn't call gemfile_sorted" do + expect(Ordinare::Check).not_to receive(:gemfile_sorted?) + + Ordinare.parse_args + end + + it "doesn't call sort_gemfile" do + expect(Ordinare::Sort).not_to receive(:sort_gemfile) + + Ordinare.parse_args + end end + end + + context "get help" do + context "using -h" do + before { ARGV = ["-h"] } - it "sorts Gemfile with groups" do - group_gemfile = "spec/fixtures/group_gemfile/Gemfile" - Ordinare.sort(false, group_gemfile) + it "doesn't call gemfile_sorted" do + expect(Ordinare::Check).not_to receive(:gemfile_sorted?) - same_files = FileUtils.identical?("#{group_gemfile}.ordered", "#{group_gemfile}.ordinare") - expect(same_files).to be_truthy + Ordinare.parse_args + end + + it "doesn't call sort_gemfile" do + expect(Ordinare::Sort).not_to receive(:sort_gemfile) + + Ordinare.parse_args + end end - it "sorts complicated Gemfile" do - complex_gemfile = "spec/fixtures/complex_gemfile/Gemfile" - Ordinare.sort(false, complex_gemfile) + context "using --help" do + before { ARGV = ["--help"] } + + it "doesn't call gemfile_sorted" do + expect(Ordinare::Check).not_to receive(:gemfile_sorted?) + + Ordinare.parse_args + end + + it "doesn't call sort_gemfile" do + expect(Ordinare::Sort).not_to receive(:sort_gemfile) - same_files = FileUtils.identical?("#{complex_gemfile}.ordered", "#{complex_gemfile}.ordinare") - expect(same_files).to be_truthy + Ordinare.parse_args + end end end end