dossier 2.12.2 → 2.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -6
  3. data/Rakefile +12 -5
  4. data/VERSION +1 -0
  5. data/app/controllers/dossier/reports_controller.rb +1 -1
  6. data/app/views/dossier/reports/show.html.haml +1 -1
  7. data/lib/dossier.rb +1 -1
  8. data/lib/dossier/client.rb +4 -1
  9. data/lib/dossier/configuration.rb +10 -5
  10. data/lib/dossier/{naming.rb → model.rb} +10 -2
  11. data/lib/dossier/multi_report.rb +1 -1
  12. data/lib/dossier/query.rb +1 -1
  13. data/lib/dossier/report.rb +13 -10
  14. data/lib/dossier/responder.rb +2 -0
  15. data/lib/dossier/result.rb +29 -12
  16. data/lib/dossier/version.rb +1 -1
  17. data/lib/generators/dossier/views/templates/show.html.haml +1 -1
  18. data/spec/dossier/adapter/active_record_spec.rb +4 -4
  19. data/spec/dossier/client_spec.rb +19 -19
  20. data/spec/dossier/configuration_spec.rb +29 -9
  21. data/spec/dossier/{naming_spec.rb → model_spec.rb} +6 -1
  22. data/spec/dossier/query_spec.rb +12 -12
  23. data/spec/dossier/report_spec.rb +7 -7
  24. data/spec/dossier/responder_spec.rb +5 -5
  25. data/spec/dossier/result_spec.rb +5 -5
  26. data/spec/dossier/stream_csv_spec.rb +5 -3
  27. data/spec/dossier/version_spec.rb +8 -0
  28. data/spec/dossier_spec.rb +4 -4
  29. data/spec/dummy/Rakefile +4 -0
  30. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  31. data/spec/dummy/app/reports/cats/are/super_fun_report.rb +13 -1
  32. data/spec/dummy/app/reports/employee_report.rb +14 -1
  33. data/spec/dummy/app/reports/employee_with_custom_view_report.rb +5 -1
  34. data/spec/dummy/bin/rails +4 -0
  35. data/spec/dummy/bin/rake +4 -0
  36. data/spec/dummy/config/application.rb +30 -0
  37. data/spec/dummy/config/database.yml +6 -5
  38. data/spec/dummy/db/{test.sqlite3 → dossier_test.sqlite3} +0 -0
  39. data/spec/dummy/log/development.log +0 -0
  40. data/spec/dummy/log/test.log +21983 -0
  41. data/spec/features/employee_spec.rb +13 -4
  42. data/spec/fixtures/db/postgresql.yml +4 -0
  43. data/spec/fixtures/db/postgresql.yml.example +5 -0
  44. data/spec/fixtures/db/postgresql.yml.travis +4 -0
  45. data/spec/fixtures/db/sqlite3.yml +1 -1
  46. data/spec/fixtures/reports/employee.csv +3 -3
  47. data/spec/fixtures/reports/employee.xls +3 -3
  48. data/spec/generators/dossier/views/views_spec.rb +17 -10
  49. data/spec/routing/dossier_routes_spec.rb +1 -1
  50. data/spec/spec_helper.rb +7 -10
  51. data/spec/support/factory.rb +38 -0
  52. metadata +57 -44
  53. data/spec/dummy/config/database.yml.example +0 -13
  54. data/spec/dummy/config/database.yml.travis +0 -5
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Dossier::Configuration do
4
4
 
5
- let(:connection_options){ YAML.load_file(Rails.root.join('config', 'dossier.yml'))[Rails.env].symbolize_keys }
5
+ let(:connection_options){ YAML.load(ERB.new(File.read Rails.root.join('config', 'dossier.yml')).result)[Rails.env].symbolize_keys }
6
6
  let(:old_database_url) { ENV.delete "DATABASE_URL"}
7
7
 
8
8
  before :each do
@@ -10,13 +10,17 @@ describe Dossier::Configuration do
10
10
  @config = Dossier.configuration
11
11
  end
12
12
 
13
+ after :each do
14
+ ENV.delete "DATABASE_URL" if ENV.has_key? "DATABASE_URL"
15
+ end
16
+
13
17
  after :each do
14
18
  ENV["DATABASE_URL"] = old_database_url
15
19
  end
16
20
 
17
21
  describe "defaults" do
18
22
  it "uses the rails configuration directory for the config path" do
19
- @config.config_path.should eq(Rails.root.join("config", "dossier.yml"))
23
+ expect(@config.config_path).to eq(Rails.root.join("config", "dossier.yml"))
20
24
  end
21
25
  end
22
26
 
@@ -30,20 +34,36 @@ describe Dossier::Configuration do
30
34
  end
31
35
 
32
36
  it "uses config/dossier.yml to setup the client" do
33
- ENV.delete "DATABASE_URL" if ENV.has_key? "DATABASE_URL"
34
37
  expect(Dossier::Client).to receive(:new).with(connection_options)
35
38
  Dossier.configure
36
39
  end
37
40
 
38
- it "will raise an exception if config/dossier.yml cannot be read" do
39
- config_path = Rails.root.join('config')
40
- FileUtils.mv config_path.join('dossier.yml'), config_path.join('dossier.yml.test')
41
- expect { Dossier.configure }.to raise_error(Dossier::ConfigurationMissingError)
42
- FileUtils.mv config_path.join('dossier.yml.test'), config_path.join('dossier.yml')
41
+ describe "missing a dossier.yml" do
42
+ let(:config_path) { Rails.root.join('config') }
43
+
44
+ before :each do
45
+ FileUtils.mv config_path.join('dossier.yml'),
46
+ config_path.join('dossier.yml.test')
47
+ end
48
+
49
+ after :each do
50
+ FileUtils.mv config_path.join('dossier.yml.test'),
51
+ config_path.join('dossier.yml')
52
+ end
53
+
54
+ it "will not raise an exception if config/dossier.yml cannot be read and DATABSE_URL is set" do
55
+ ENV['DATABASE_URL'] = "mysql2://localhost/dossier_test"
56
+ expect { Dossier.configure }.not_to raise_error
57
+ end
58
+
59
+ it "will raise an error if connection options is blank" do
60
+ expect { Dossier.configure }.to(
61
+ raise_error(Dossier::ConfigurationMissingError))
62
+ end
43
63
  end
44
64
 
45
65
  it "will setup the connection options" do
46
- @config.connection_options.should be_a(Hash)
66
+ expect(@config.connection_options).to be_a(Hash)
47
67
  end
48
68
  end
49
69
 
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Dossier::Naming do
3
+ describe Dossier::Model do
4
4
  describe "report naming" do
5
5
  let(:klass) { HelloMyFriendsReport }
6
6
  let(:name) { 'hello_my_friends' }
@@ -13,6 +13,11 @@ describe Dossier::Naming do
13
13
  expect(described_class.name_to_class(name)).to eq(klass)
14
14
  end
15
15
 
16
+ it "has a to_model" do
17
+ instance = klass.new
18
+ expect(instance.to_model).to eq(instance)
19
+ end
20
+
16
21
  describe "with namespaces" do
17
22
  let(:klass) { Cats::Are::SuperFunReport }
18
23
  let(:name) { 'cats/are/super_fun' }
@@ -6,8 +6,8 @@ describe Dossier::Query do
6
6
  let(:query) { Dossier::Query.new(report) }
7
7
 
8
8
  before :each do
9
- report.stub(:salary).and_return(2)
10
- report.stub(:ids).and_return([1,2,3])
9
+ allow(report).to receive(:salary).and_return(2)
10
+ allow(report).to receive(:ids).and_return([1,2,3])
11
11
  end
12
12
 
13
13
  describe "replacing symbols by calling methods of the same name" do
@@ -17,10 +17,10 @@ describe Dossier::Query do
17
17
  context "when the methods return single values" do
18
18
 
19
19
  before :each do
20
- report.stub(:sql).and_return("SELECT * FROM employees WHERE id = :id OR girth < :girth OR hired_on = :hired_on")
21
- report.stub(:id).and_return(92)
22
- report.stub(:girth).and_return(3.14)
23
- report.stub(:hired_on).and_return('2013-03-29')
20
+ allow(report).to receive(:sql).and_return("SELECT * FROM employees WHERE id = :id OR girth < :girth OR hired_on = :hired_on")
21
+ allow(report).to receive(:id).and_return(92)
22
+ allow(report).to receive(:girth).and_return(3.14)
23
+ allow(report).to receive(:hired_on).and_return('2013-03-29')
24
24
  end
25
25
 
26
26
  it "escapes the values" do
@@ -39,8 +39,8 @@ describe Dossier::Query do
39
39
  context "when the methods return arrays" do
40
40
 
41
41
  before :each do
42
- report.stub(:sql).and_return("SELECT * FROM employees WHERE stuff IN :stuff")
43
- report.stub(:stuff).and_return([38, 'blue', 'mandible', 2])
42
+ allow(report).to receive(:sql).and_return("SELECT * FROM employees WHERE stuff IN :stuff")
43
+ allow(report).to receive(:stuff).and_return([38, 'blue', 'mandible', 2])
44
44
  end
45
45
 
46
46
  it "escapes each value in the array" do
@@ -60,14 +60,14 @@ describe Dossier::Query do
60
60
  context "when it's another string that includes :" do
61
61
 
62
62
  it "does not escape a namespaced constant" do
63
- report.stub(:sql).and_return("SELECT * FROM employees WHERE type = 'Foo::Bar'")
64
- query.should_not_receive(:Bar)
63
+ allow(report).to receive(:sql).and_return("SELECT * FROM employees WHERE type = 'Foo::Bar'")
64
+ expect(query).not_to receive(:Bar)
65
65
  query.to_s
66
66
  end
67
67
 
68
68
  it "does not escape a top-level constant" do
69
- report.stub(:sql).and_return("SELECT * FROM employees WHERE type = '::Foo'")
70
- query.should_not_receive(:Foo)
69
+ allow(report).to receive(:sql).and_return("SELECT * FROM employees WHERE type = '::Foo'")
70
+ expect(query).not_to receive(:Foo)
71
71
  query.to_s
72
72
  end
73
73
 
@@ -5,7 +5,7 @@ describe Dossier::Report do
5
5
  let(:report) { TestReport.new(:foo => 'bar') }
6
6
 
7
7
  it "has a report name" do
8
- TestReport.report_name.should eq('test')
8
+ expect(TestReport.report_name).to eq('test')
9
9
  end
10
10
 
11
11
  it "has a template name that is the report name" do
@@ -29,15 +29,15 @@ describe Dossier::Report do
29
29
  end
30
30
 
31
31
  it "takes options when initializing" do
32
- report.options.should eq('foo' => 'bar')
32
+ expect(report.options).to eq('foo' => 'bar')
33
33
  end
34
34
 
35
35
  it 'generates column headers' do
36
- report.format_header('Foo').should eq 'Foo'
36
+ expect(report.format_header('Foo')).to eq 'Foo'
37
37
  end
38
38
 
39
39
  it 'allows for column header customization' do
40
- report_with_custom_header.format_header(:generic).should eq 'customized'
40
+ expect(report_with_custom_header.format_header(:generic)).to eq 'customized'
41
41
  end
42
42
 
43
43
  it "has a formatted title" do
@@ -62,8 +62,8 @@ describe Dossier::Report do
62
62
  end
63
63
 
64
64
  it "has callbacks for execute" do
65
- Dossier.client.stub(:execute).and_return([])
66
- report.stub(:before_test_for_build_query)
65
+ allow(Dossier.client).to receive(:execute).and_return([])
66
+ allow(report).to receive(:before_test_for_build_query)
67
67
  expect(report).to receive(:after_test_for_execute)
68
68
  report.run
69
69
  end
@@ -86,7 +86,7 @@ describe Dossier::Report do
86
86
  it "will cache the results of the run in `results`" do
87
87
  report = EmployeeReport.new
88
88
  report.run
89
- report.results.should_not be_nil
89
+ expect(report.results).not_to be_nil
90
90
  end
91
91
  end
92
92
 
@@ -2,18 +2,18 @@ require 'spec_helper'
2
2
 
3
3
  describe Dossier::Responder do
4
4
 
5
- def stub_out_report_results(report)
5
+ def mock_out_report_results(report)
6
6
  report.tap { |r|
7
- r.stub(:results).and_return(results)
8
- r.stub(:raw_results).and_return(results)
7
+ allow(r).to receive(:results).and_return(results)
8
+ allow(r).to receive(:raw_results).and_return(results)
9
9
  }
10
10
  end
11
11
 
12
12
  let(:results) { double(arrays: [%w[hi], %w[there]], hashes: [{hi: 'there'}]) }
13
13
  let(:report) { EmployeeReport.new }
14
- let(:reports) { [stub_out_report_results(report)] }
14
+ let(:reports) { [mock_out_report_results(report)] }
15
15
  let(:controller) {
16
- ActionController::Base.new.tap { |controller| controller.stub(:headers).and_return({}) }
16
+ ActionController::Base.new.tap { |controller| allow(controller).to receive(:headers).and_return({}) }
17
17
  }
18
18
  let(:responder) { described_class.new(controller, reports, {}) }
19
19
 
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Dossier::Result do
4
4
 
5
- module AbstractStub
5
+ module AbstractMock
6
6
  def each
7
7
  adapter_results.rows.each do |row|
8
8
  yield row
@@ -17,7 +17,7 @@ describe Dossier::Result do
17
17
  let(:report) { TestReport.new }
18
18
  let(:result_row) { {'mascot' => 'platapus', 'cheese' => 'bleu'} }
19
19
  let(:adapter_result) { double(:adapter_result, rows: [result_row.values], headers: result_row.keys) }
20
- let(:result_class) { Class.new(described_class) { include AbstractStub } }
20
+ let(:result_class) { Class.new(described_class) { include AbstractMock } }
21
21
  let(:result) { result_class.new(adapter_result, report) }
22
22
 
23
23
  it "requires each to be overridden" do
@@ -51,7 +51,7 @@ describe Dossier::Result do
51
51
  end
52
52
 
53
53
  it "can return an array of arrays" do
54
- result.stub(:headers).and_return(%w[mascot cheese])
54
+ allow(result).to receive(:headers).and_return(%w[mascot cheese])
55
55
  expect(result.arrays).to eq([%w[mascot cheese], %w[platapus bleu]])
56
56
  end
57
57
 
@@ -122,7 +122,7 @@ describe Dossier::Result do
122
122
  let(:adapter_result_rows) { 7.times.map { result_row.values } }
123
123
 
124
124
  before :each do
125
- adapter_result.stub(:rows).and_return(adapter_result_rows)
125
+ allow(adapter_result).to receive(:rows).and_return(adapter_result_rows)
126
126
  end
127
127
 
128
128
  it "has 4 result rows" do
@@ -157,7 +157,7 @@ describe Dossier::Result do
157
157
  end
158
158
 
159
159
  it "does not format the results" do
160
- result.should_not_receive(:format)
160
+ expect(result).not_to receive(:format)
161
161
  result.each { |result| }
162
162
  end
163
163
 
@@ -57,16 +57,18 @@ describe Dossier::StreamCSV do
57
57
  describe "exceptions" do
58
58
  let(:output) { String.new }
59
59
  let(:error) { "Woooooooo cats are fluffy!" }
60
- before(:each) { collection[0].stub(:to_csv).and_return { raise error } }
60
+ before(:each) {
61
+ allow(collection[0]).to receive(:to_csv).and_raise(error)
62
+ }
61
63
 
62
64
  it "provides a backtrace if local request" do
63
- Rails.application.config.stub(:consider_all_requests_local).and_return(true)
65
+ allow(Rails.application.config).to receive(:consider_all_requests_local).and_return(true)
64
66
  streamer.each { |line| output << line }
65
67
  expect(output).to include(error)
66
68
  end
67
69
 
68
70
  it "provides a simple error if not a local request" do
69
- Rails.application.config.stub(:consider_all_requests_local).and_return(false)
71
+ allow(Rails.application.config).to receive(:consider_all_requests_local).and_return(false)
70
72
  streamer.each { |line| output << line }
71
73
  expect(output).to match(/something went wrong/)
72
74
  end
@@ -0,0 +1,8 @@
1
+ RSpec.describe Dossier::VERSION do
2
+
3
+ it "is a string" do
4
+ expect(subject).to be_a String
5
+ end
6
+
7
+ end
8
+
@@ -2,17 +2,17 @@ require 'spec_helper'
2
2
 
3
3
  describe Dossier do
4
4
  it "is a module" do
5
- Dossier.should be_a(Module)
5
+ expect(Dossier).to be_a(Module)
6
6
  end
7
7
 
8
8
  it "is configurable" do
9
9
  Dossier.configure
10
- Dossier.configuration.should_not be_nil
10
+ expect(Dossier.configuration).to_not be_nil
11
11
  end
12
12
 
13
13
  it "has a configuration" do
14
14
  Dossier.configure
15
- Dossier.configuration.should be_a(Dossier::Configuration)
15
+ expect(Dossier.configuration).to be_a(Dossier::Configuration)
16
16
  end
17
17
 
18
18
  it "allows configuration via a block" do
@@ -20,7 +20,7 @@ describe Dossier do
20
20
  Dossier.configure do |config|
21
21
  config.client = some_client
22
22
  end
23
- Dossier.configuration.client.should eq(some_client)
23
+ expect(Dossier.configuration.client).to eq(some_client)
24
24
  end
25
25
 
26
26
  it "exposes the configurations client via Dossier.client" do
@@ -0,0 +1,4 @@
1
+ require File.expand_path('../config/application', __FILE__)
2
+
3
+ Dummy::Application.load_tasks
4
+
@@ -0,0 +1,3 @@
1
+ ApplicationController = Class.new(ActionController::Base) do
2
+ protect_from_forgery with: :exception
3
+ end
@@ -2,7 +2,19 @@ module Cats
2
2
  module Are
3
3
  class SuperFunReport < Dossier::Report
4
4
  def sql
5
- "select 'cats', 'are', 'super', 'fun'"
5
+ "select #{selections.join(', ')}"
6
+ end
7
+
8
+ def selections
9
+ columns = %w(cats are super fun)
10
+ selections = columns.map { |x| "'#{x}' as #{x}" }
11
+ if ENV['DOSSIER_DB'].to_s === 'postgresql'
12
+ selections.map! { |x|
13
+ parts = x.split(' as ')
14
+ "'#{parts[0][1..-2]}'::character(7) as #{parts[1]}"
15
+ }
16
+ end
17
+ selections
6
18
  end
7
19
  end
8
20
  end
@@ -55,12 +55,17 @@ class EmployeeReport < Dossier::Report
55
55
  @names ||= options.fetch(:names) { [] }.dup
56
56
  end
57
57
 
58
+ def display_column?(name)
59
+ name != 'id'
60
+ end
61
+
58
62
  def format_salary(amount, row)
59
63
  return "Who's Asking?" if row[:division] == "Corporate Malfeasance"
60
64
  formatter.number_to_currency(amount)
61
65
  end
62
66
 
63
67
  def format_hired_on(date)
68
+ date = Date.parse(date) if String === date
64
69
  date.to_s(:db)
65
70
  end
66
71
 
@@ -69,11 +74,19 @@ class EmployeeReport < Dossier::Report
69
74
  end
70
75
 
71
76
  def format_suspended(value)
72
- value.to_i == 1 ? 'Yes' : 'No'
77
+ value.to_s.in?(%w(1 t)) ? 'Yes' : 'No'
73
78
  end
74
79
 
75
80
  def example_before_hook
76
81
  # do some stuff
77
82
  end
78
83
 
84
+ def raw_results
85
+ super
86
+ results = query_results.rows.map { |qr|
87
+ qr.tap { |q| q[4] = format_suspended(q[4]) }
88
+ }
89
+ @raw_results ||= Result::Unformatted.new(results, self)
90
+ end
91
+
79
92
  end
@@ -6,7 +6,7 @@ class EmployeeWithCustomViewReport < Dossier::Report
6
6
  end
7
7
 
8
8
  def sql
9
- "SELECT * FROM employees WHERE suspended = true"
9
+ "SELECT * FROM employees WHERE suspended = :suspended"
10
10
  end
11
11
 
12
12
  def dragon_color
@@ -17,6 +17,10 @@ class EmployeeWithCustomViewReport < Dossier::Report
17
17
  @formatter ||= CustomFormatter
18
18
  end
19
19
 
20
+ def suspended
21
+ true
22
+ end
23
+
20
24
  module CustomFormatter
21
25
  extend Dossier::Formatter
22
26
  def margery_butts(word)
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require APP_PATH
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/application'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,30 @@
1
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('../../../../Gemfile', __FILE__)
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+
6
+ Bundler.setup
7
+
8
+ require "rails/all"
9
+
10
+ Bundler.require
11
+
12
+ module Dummy
13
+ class Application < ::Rails::Application
14
+ config.cache_classes = true
15
+ config.active_support.deprecation = :stderr
16
+ config.eager_load = false
17
+ config.action_controller.allow_forgery_protection = false
18
+
19
+ # Raise exceptions instead of rendering exception templates
20
+ config.action_dispatch.show_exceptions = false
21
+ # because this belongs here for some reason...??? also in spec_helper
22
+ # thanks rails 5 :/
23
+ config.active_support.test_order = :random
24
+
25
+ config.secret_token = config.secret_key_base =
26
+ 'http://s3-ec.buzzfed.com/static/enhanced/webdr03/2013/5/25/8/anigif_enhanced-buzz-11857-1369483324-0.gif'
27
+ end
28
+ end
29
+
30
+ Dummy::Application.initialize!