From dd228a4dd42a3410e638971475a8b291f6edbcd5 Mon Sep 17 00:00:00 2001 From: Tomasz Gieniusz Date: Fri, 12 Oct 2012 18:20:07 +0200 Subject: [PATCH] lazy loading and firsts tests --- .rspec | 1 + bin/git_stats | 8 +++++- git_stats.gemspec | 1 + lib/git_stats/cli.rb | 39 ++++--------------------- lib/git_stats/generator.rb | 19 +++++++++++-- lib/git_stats/git_data/author.rb | 10 +++++-- lib/git_stats/git_data/repo.rb | 41 +++++++++------------------ lib/git_stats/stats_view/view_data.rb | 4 +-- spec/cli_spec.rb | 19 +++++++++++++ spec/generator_spec.rb | 31 ++++++++++++++++++++ spec/spec_helper.rb | 1 + templates/index.haml | 2 +- 12 files changed, 105 insertions(+), 71 deletions(-) create mode 100644 .rspec create mode 100644 spec/cli_spec.rb create mode 100644 spec/generator_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.rspec b/.rspec new file mode 100644 index 000000000..114486d9b --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--color --format documentation diff --git a/bin/git_stats b/bin/git_stats index c1d49f558..e434770de 100755 --- a/bin/git_stats +++ b/bin/git_stats @@ -6,4 +6,10 @@ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib) # start up the CLI require "git_stats/cli" -GitStats::CLI.start(*ARGV) \ No newline at end of file + +begin + cli = GitStats::CLI.new + cli.start(*ARGV) +rescue => e + puts e.message +end \ No newline at end of file diff --git a/git_stats.gemspec b/git_stats.gemspec index 1065760e9..80fafe944 100644 --- a/git_stats.gemspec +++ b/git_stats.gemspec @@ -26,4 +26,5 @@ Gem::Specification.new do |gem| gem.add_development_dependency('rake') gem.add_development_dependency('pry') + gem.add_development_dependency('rspec') end diff --git a/lib/git_stats/cli.rb b/lib/git_stats/cli.rb index 182fe07f4..db8916988 100644 --- a/lib/git_stats/cli.rb +++ b/lib/git_stats/cli.rb @@ -2,40 +2,11 @@ require "git_stats" class GitStats::CLI - def self.start(*args) - if args.size == 2 - repo_path, out_path = args - validate(repo_path, out_path) - GitStats::Generator.new(repo_path, out_path).generate - #Launchy.open("#{out_path}/index.html") - else - puts "Wrong number of arguments" - help - end + def start(*args) + raise "Wrong number of arguments\nUsage: git_stats repo_path output_path" unless args.size == 2 + + repo_path, out_path = args + GitStats::Generator.new(repo_path, out_path).generate end - private - def self.help - puts "Usage: git_stats repo_path output_path" - exit 0 - end - - def self.validate(repo_path, out_path) - validate_repo(repo_path) - validate_out(out_path) - end - - def self.validate_repo(repo_path) - unless Dir.exists?("#{repo_path}/.git") - puts "#{repo_path} is not a git repository" - help - end - end - - def self.validate_out(out_path) - unless Dir.exists?("#{out_path}") - puts "#{out_path} doesn't exist" - help - end - end end diff --git a/lib/git_stats/generator.rb b/lib/git_stats/generator.rb index 40b3466e8..8987bcd1b 100644 --- a/lib/git_stats/generator.rb +++ b/lib/git_stats/generator.rb @@ -5,14 +5,27 @@ module GitStats end def generate - repo = GitData::Repo.new(@repo_path) - repo.gather_all_data + validate_paths + repo = GitData::Repo.new(@repo_path) view_data = StatsView::ViewData.new(repo) - view_data.generate_charts StatsView::View.render_all(view_data, @out_path) end + + private + def validate_paths + validate_repo_path + validate_out_path + end + + def validate_repo_path + raise ArgumentError, "#@repo_path is not a git repository" unless Dir.exists?("#@repo_path/.git") + end + + def validate_out_path + raise ArgumentError, "#@out_path is not a directory" unless Dir.exists?(@out_path) + end end end \ No newline at end of file diff --git a/lib/git_stats/git_data/author.rb b/lib/git_stats/git_data/author.rb index b750ed344..b5c1a63ca 100644 --- a/lib/git_stats/git_data/author.rb +++ b/lib/git_stats/git_data/author.rb @@ -5,7 +5,7 @@ module GitStats class Author include HashInitializable - attr_accessor :name, :email + attr_reader :repo, :name, :email def add_commit(commit) commits << commit @@ -13,12 +13,16 @@ module GitStats end def commits - @commits ||= [] + @commits ||= repo.commits.select { |hash, commit| commit.author == self } end def activity - @activity ||= Activity.new + @activity ||= commits.values.inject(Activity.new) do |activity, commit| + activity.add_commit(commit) + activity + end end + end end end \ No newline at end of file diff --git a/lib/git_stats/git_data/repo.rb b/lib/git_stats/git_data/repo.rb index 7282690da..8cd8272d3 100644 --- a/lib/git_stats/git_data/repo.rb +++ b/lib/git_stats/git_data/repo.rb @@ -7,44 +7,30 @@ module GitStats @path = path end - def gather_all_data - project_version - project_name - gather_authors - gather_commits - end - - def gather_authors - Command.new(self, 'git shortlog -se HEAD').run.each_line do |author| - name, email = author.split(/\t/)[1].strip.scan(/(.*)<(.*)>/).first.map(&:strip) - authors[email] = Author.new(name: name, email: email) + def authors + @authors ||= Command.new(self, 'git shortlog -se HEAD').run.lines.inject({}) do |authors, line| + name, email = line.split(/\t/)[1].strip.scan(/(.*)<(.*)>/).first.map(&:strip) + authors[email] = Author.new(repo: self, name: name, email: email) + authors end end - def gather_commits - Command.new(self, 'git rev-list --pretty=format:"%h|%at|%ai|%aE" HEAD | grep -v commit').run.lines.each_with_index do |commit_line, i| + def commits + @commits ||= Command.new(self, 'git rev-list --pretty=format:"%h|%at|%ai|%aE" HEAD | grep -v commit').run.lines.inject({}) do |commits, commit_line| hash, stamp, date, author_email = commit_line.split('|').map(&:strip) author = authors[author_email] date = DateTime.parse(date) - commit = commits[hash] = Commit.new(repo: self, hash: hash, stamp: stamp, date: date, author: author) - commit.gather_all_data - - activity.add_commit(commit) - author.add_commit(commit) + commits[hash] = Commit.new(repo: self, hash: hash, stamp: stamp, date: date, author: author) + commits end end - def authors - @authors ||= {} - end - - def commits - @commits ||= {} - end - def activity - @activity ||= Activity.new + @activity ||= commits.values.inject(Activity.new) do |activity, commit| + activity.add_commit(commit) + activity + end end def project_version @@ -54,6 +40,7 @@ module GitStats def project_name @project_name ||= Pathname(path).basename.to_s end + end end end \ No newline at end of file diff --git a/lib/git_stats/stats_view/view_data.rb b/lib/git_stats/stats_view/view_data.rb index 937ad3319..454dc4afe 100644 --- a/lib/git_stats/stats_view/view_data.rb +++ b/lib/git_stats/stats_view/view_data.rb @@ -10,8 +10,8 @@ module GitStats @repo = repo end - def generate_charts - @h = LazyHighCharts::HighChart.new('graph') do |f| + def h + @h ||= LazyHighCharts::HighChart.new('graph') do |f| f.chart(type: "column") f.title(text: "Commits") f.xAxis(categories: Date::ABBR_DAYNAMES) diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb new file mode 100644 index 000000000..79477447b --- /dev/null +++ b/spec/cli_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe GitStats::CLI do + let(:repo_path) { 'repo_path' } + let(:out_path) { 'out_path' } + + it 'should invoke generator with console arguments given' do + generator = double('generator') + GitStats::Generator.should_receive(:new).with(repo_path, out_path).and_return(generator) + generator.should_receive(:generate) + + subject.start(repo_path, out_path) + end + + it 'should raise error when 2 arguments are not given' do + expect { subject.start("only one argument") }.to raise_error + expect { subject.start("too", "much", "arguments") }.to raise_error + end +end \ No newline at end of file diff --git a/spec/generator_spec.rb b/spec/generator_spec.rb new file mode 100644 index 000000000..17dfa821a --- /dev/null +++ b/spec/generator_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe GitStats::Generator do + let(:repo_path) { 'repo_path' } + let(:out_path) { 'out_path' } + let(:generator) { GitStats::Generator.new(repo_path, out_path) } + + before { Dir.stub!(:exists? => true) } + + it 'should raise exception if given repo path is not a git repository' do + Dir.should_receive(:exists?).with("#{repo_path}/.git").and_return(false) + expect { generator.generate }.to raise_error(ArgumentError) + end + + it "should raise exception if given out directory doesn't exist" do + Dir.should_receive(:exists?).with(out_path).and_return(false) + expect { generator.generate }.to raise_error(ArgumentError) + end + + it 'should render all templates with view data for this repo' do + repo = double('repo') + GitStats::GitData::Repo.should_receive(:new).with(repo_path).and_return(repo) + + view_data = double('view_data') + GitStats::StatsView::ViewData.should_receive(:new).with(repo).and_return(view_data) + + GitStats::StatsView::View.should_receive(:render_all).with(view_data, out_path) + + generator.generate + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 000000000..ae1aba41a --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1 @@ +require 'git_stats' diff --git a/templates/index.haml b/templates/index.haml index 9c2c20035..aa78a4c85 100644 --- a/templates/index.haml +++ b/templates/index.haml @@ -1,4 +1,4 @@ %p= repo.project_name %p= repo.project_version -= high_chart("my_id", @h) \ No newline at end of file += high_chart("my_id", h) \ No newline at end of file