dossier 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.markdown +181 -0
  3. data/Rakefile +27 -0
  4. data/app/assets/javascripts/dossier/application.js +15 -0
  5. data/app/assets/stylesheets/dossier/application.css +13 -0
  6. data/app/controllers/dossier/application_controller.rb +4 -0
  7. data/app/controllers/dossier/reports_controller.rb +34 -0
  8. data/app/helpers/dossier/application_helper.rb +4 -0
  9. data/app/views/dossier/reports/show.html.haml +21 -0
  10. data/config/routes.rb +5 -0
  11. data/lib/dossier.rb +31 -0
  12. data/lib/dossier/adapter/active_record.rb +40 -0
  13. data/lib/dossier/adapter/active_record/result.rb +24 -0
  14. data/lib/dossier/client.rb +52 -0
  15. data/lib/dossier/configuration.rb +28 -0
  16. data/lib/dossier/engine.rb +7 -0
  17. data/lib/dossier/formatter.rb +33 -0
  18. data/lib/dossier/query.rb +30 -0
  19. data/lib/dossier/report.rb +69 -0
  20. data/lib/dossier/result.rb +67 -0
  21. data/lib/dossier/stream_csv.rb +24 -0
  22. data/lib/dossier/version.rb +3 -0
  23. data/lib/tasks/dossier_tasks.rake +4 -0
  24. data/spec/dossier/adapter/active_record/result_spec.rb +31 -0
  25. data/spec/dossier/adapter/active_record_spec.rb +54 -0
  26. data/spec/dossier/client_spec.rb +109 -0
  27. data/spec/dossier/configuration_spec.rb +35 -0
  28. data/spec/dossier/formatter_spec.rb +39 -0
  29. data/spec/dossier/query_spec.rb +59 -0
  30. data/spec/dossier/report_spec.rb +67 -0
  31. data/spec/dossier/result_spec.rb +119 -0
  32. data/spec/dossier_spec.rb +31 -0
  33. data/spec/dummy/README.rdoc +261 -0
  34. data/spec/dummy/Rakefile +7 -0
  35. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  36. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  37. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  38. data/spec/dummy/app/controllers/site_controller.rb +5 -0
  39. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  40. data/spec/dummy/app/views/dossier/reports/suspended_employee.html.haml +1 -0
  41. data/spec/dummy/app/views/dossier/reports/total.html.haml +11 -0
  42. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  43. data/spec/dummy/config.ru +4 -0
  44. data/spec/dummy/config/application.rb +56 -0
  45. data/spec/dummy/config/boot.rb +10 -0
  46. data/spec/dummy/config/database.yml.example +13 -0
  47. data/spec/dummy/config/environment.rb +9 -0
  48. data/spec/dummy/config/environments/development.rb +37 -0
  49. data/spec/dummy/config/environments/production.rb +67 -0
  50. data/spec/dummy/config/environments/test.rb +37 -0
  51. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  52. data/spec/dummy/config/initializers/inflections.rb +15 -0
  53. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  54. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  55. data/spec/dummy/config/initializers/session_store.rb +8 -0
  56. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  57. data/spec/dummy/config/locales/en.yml +5 -0
  58. data/spec/dummy/config/routes.rb +5 -0
  59. data/spec/dummy/config/setup_load_paths.rb +15 -0
  60. data/spec/dummy/db/schema.rb +24 -0
  61. data/spec/dummy/dossier_test +0 -0
  62. data/spec/dummy/public/404.html +26 -0
  63. data/spec/dummy/public/422.html +26 -0
  64. data/spec/dummy/public/500.html +25 -0
  65. data/spec/dummy/public/favicon.ico +0 -0
  66. data/spec/dummy/script/rails +6 -0
  67. data/spec/fixtures/customized_employee_report.html +38 -0
  68. data/spec/fixtures/db/mysql2.yml.example +4 -0
  69. data/spec/fixtures/db/sqlite3.yml.example +2 -0
  70. data/spec/fixtures/employee_report.csv +4 -0
  71. data/spec/fixtures/employee_report.html +54 -0
  72. data/spec/fixtures/employee_report_with_footer.html +56 -0
  73. data/spec/fixtures/employee_with_custom_client.html +54 -0
  74. data/spec/requests/employee_report_spec.rb +52 -0
  75. data/spec/requests/employee_with_custom_client_spec.rb +13 -0
  76. data/spec/routing/dossier_routes_spec.rb +11 -0
  77. data/spec/spec_helper.rb +36 -0
  78. data/spec/support/factory.rb +86 -0
  79. data/spec/support/reports/employee_report.rb +78 -0
  80. data/spec/support/reports/employee_with_custom_client.rb +10 -0
  81. data/spec/support/reports/sqlite_employee_report.rb +15 -0
  82. data/spec/support/reports/supended_employee_report.rb +7 -0
  83. data/spec/support/reports/test_report.rb +4 -0
  84. data/spec/support/reports/total_report.rb +35 -0
  85. metadata +361 -0
File without changes
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/404.html -->
21
+ <div class="dialog">
22
+ <h1>The page you were looking for doesn't exist.</h1>
23
+ <p>You may have mistyped the address or the page may have moved.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ </div>
24
+ </body>
25
+ </html>
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <link href="/assets/application.css" media="all" rel="stylesheet" type="text/css" />
6
+ <script src="/assets/application.js" type="text/javascript"></script>
7
+
8
+ </head>
9
+ <body>
10
+
11
+ <h1>Employee Report</h1>
12
+ <table>
13
+ <thead>
14
+ <tr>
15
+ <th>Id</th>
16
+ <th>Name</th>
17
+ <th>Division</th>
18
+ <th>Salary</th>
19
+ <th>Suspended</th>
20
+ <th>Hired On</th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <tr>
25
+ <td>2</td>
26
+ <td>Employee Jimmy Jackalope, Jr.</td>
27
+ <td>Tedious Toiling</td>
28
+ <td>$20,000.00</td>
29
+ <td>Yes</td>
30
+ <td>2013-01-11</td>
31
+ </tr>
32
+ </tbody>
33
+ </table>
34
+ <a href="/reports/employee.csv?options%5Bdivisions%5D%5B%5D=Tedious+Toiling&amp;options%5Bnames%5D%5B%5D=Jimmy+Jackalope&amp;options%5Bnames%5D%5B%5D=Moustafa+McMann&amp;options%5Border%5D=desc&amp;options%5Bsalary%5D=true" class="download-csv">Download CSV</a>
35
+
36
+
37
+ </body>
38
+ </html>
@@ -0,0 +1,4 @@
1
+ database: dossier_test
2
+ host: localhost
3
+ username: root
4
+ password: something
@@ -0,0 +1,2 @@
1
+ adapter: sqlite3
2
+ database: db/test.sqlite3
@@ -0,0 +1,4 @@
1
+ Id,Name,Division,Salary,Suspended,Hired On
2
+ 3,Elise Elderberry,Corporate Malfeasance,99000,0,2013-01-11
3
+ 2,"Jimmy Jackalope, Jr.",Tedious Toiling,20000,1,2013-01-11
4
+ 1,Moustafa McMann,Zany Inventions,30000,0,2010-10-02
@@ -0,0 +1,54 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <link href="/assets/application.css" media="all" rel="stylesheet" type="text/css" />
6
+ <script src="/assets/application.js" type="text/javascript"></script>
7
+
8
+ </head>
9
+ <body>
10
+
11
+ <h1>Employee Report</h1>
12
+ <table>
13
+ <thead>
14
+ <tr>
15
+ <th>Id</th>
16
+ <th>Name</th>
17
+ <th>Division</th>
18
+ <th>Salary</th>
19
+ <th>Suspended</th>
20
+ <th>Hired On</th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <tr>
25
+ <td>3</td>
26
+ <td>Employee Elise Elderberry</td>
27
+ <td>Corporate Malfeasance</td>
28
+ <td>$99,000.00</td>
29
+ <td>No</td>
30
+ <td>2013-01-11</td>
31
+ </tr>
32
+ <tr>
33
+ <td>2</td>
34
+ <td>Employee Jimmy Jackalope, Jr.</td>
35
+ <td>Tedious Toiling</td>
36
+ <td>$20,000.00</td>
37
+ <td>Yes</td>
38
+ <td>2013-01-11</td>
39
+ </tr>
40
+ <tr>
41
+ <td>1</td>
42
+ <td>Employee Moustafa McMann</td>
43
+ <td>Zany Inventions</td>
44
+ <td>$30,000.00</td>
45
+ <td>No</td>
46
+ <td>2010-10-02</td>
47
+ </tr>
48
+ </tbody>
49
+ </table>
50
+ <a href="/reports/employee.csv" class="download-csv">Download CSV</a>
51
+
52
+
53
+ </body>
54
+ </html>
@@ -0,0 +1,56 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <link href="/assets/application.css" media="all" rel="stylesheet" type="text/css" />
6
+ <script src="/assets/application.js" type="text/javascript"></script>
7
+
8
+ </head>
9
+ <body>
10
+
11
+ <h1>Employee Report</h1>
12
+ <table>
13
+ <thead>
14
+ <tr>
15
+ <th>Id</th>
16
+ <th>Name</th>
17
+ <th>Division</th>
18
+ <th>Salary</th>
19
+ <th>Suspended</th>
20
+ <th>Hired On</th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <tr>
25
+ <td>3</td>
26
+ <td>Employee Elise Elderberry</td>
27
+ <td>Corporate Malfeasance</td>
28
+ <td>$99,000.00</td>
29
+ <td>No</td>
30
+ <td>2013-01-11</td>
31
+ </tr>
32
+ <tr>
33
+ <td>2</td>
34
+ <td>Employee Jimmy Jackalope, Jr.</td>
35
+ <td>Tedious Toiling</td>
36
+ <td>$20,000.00</td>
37
+ <td>Yes</td>
38
+ <td>2013-01-11</td>
39
+ </tr>
40
+ </tbody>
41
+ <tfoot>
42
+ <tr>
43
+ <th>1</th>
44
+ <th>Employee Moustafa McMann</th>
45
+ <th>Zany Inventions</th>
46
+ <th>$30,000.00</th>
47
+ <th>No</th>
48
+ <th>2010-10-02</th>
49
+ </tr>
50
+ </tfoot>
51
+ </table>
52
+ <a href="/reports/employee.csv?options%5Bfooter%5D=1" class="download-csv">Download CSV</a>
53
+
54
+
55
+ </body>
56
+ </html>
@@ -0,0 +1,54 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <link href="/assets/application.css" media="all" rel="stylesheet" type="text/css" />
6
+ <script src="/assets/application.js" type="text/javascript"></script>
7
+
8
+ </head>
9
+ <body>
10
+
11
+ <h1>Employee With Custom Client Report</h1>
12
+ <table>
13
+ <thead>
14
+ <tr>
15
+ <th>Id</th>
16
+ <th>Name</th>
17
+ <th>Division</th>
18
+ <th>Salary</th>
19
+ <th>Suspended</th>
20
+ <th>Hired On</th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <tr>
25
+ <td>1</td>
26
+ <td>MOUSTAFA MCMANN</td>
27
+ <td>Zany Inventions</td>
28
+ <td>30000</td>
29
+ <td>0</td>
30
+ <td>2010-10-02</td>
31
+ </tr>
32
+ <tr>
33
+ <td>2</td>
34
+ <td>JIMMY JACKALOPE, JR.</td>
35
+ <td>Tedious Toiling</td>
36
+ <td>20000</td>
37
+ <td>1</td>
38
+ <td>2013-01-11</td>
39
+ </tr>
40
+ <tr>
41
+ <td>3</td>
42
+ <td>ELISE ELDERBERRY</td>
43
+ <td>Corporate Malfeasance</td>
44
+ <td>99000</td>
45
+ <td>0</td>
46
+ <td>2013-01-11</td>
47
+ </tr>
48
+ </tbody>
49
+ </table>
50
+ <a href="/reports/employee_with_custom_client.csv" class="download-csv">Download CSV</a>
51
+
52
+
53
+ </body>
54
+ </html>
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe "employee report" do
4
+
5
+ describe "rendering HTML" do
6
+
7
+ context "when a custom view exists for the report" do
8
+
9
+ it "uses the custom view" do
10
+ get '/reports/suspended_employee'
11
+ expect(response.body).to include('<h1>Yeah. Did you get that memo?</h1>')
12
+ end
13
+
14
+ end
15
+
16
+ context "when no custom view exists for the report" do
17
+
18
+ it "creates an HTML report using its standard 'show' view" do
19
+ get '/reports/employee'
20
+ expect(response.body).to eq(File.read('spec/fixtures/employee_report.html'))
21
+ end
22
+
23
+ it "uses any options provided" do
24
+ get '/reports/employee', options: {
25
+ salary: true, order: 'desc',
26
+ names: ['Jimmy Jackalope', 'Moustafa McMann'],
27
+ divisions: ['Tedious Toiling']
28
+ }
29
+ expect(response.body).to eq(File.read('spec/fixtures/customized_employee_report.html'))
30
+ end
31
+
32
+ it "moves the specified number of rows into the footer" do
33
+ get '/reports/employee', options: {
34
+ footer: 1
35
+ }
36
+ expect(response.body).to eq(File.read('spec/fixtures/employee_report_with_footer.html'))
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+
43
+ describe "rendering CSV" do
44
+
45
+ it "creates a standard CSV report" do
46
+ get '/reports/employee.csv'
47
+ expect(response.body).to eq(File.read('spec/fixtures/employee_report.csv'))
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe EmployeeWithCustomClientReport do
4
+
5
+ describe "rendering HTML" do
6
+
7
+ it "is awesome" do
8
+ get "reports/employee_with_custom_client"
9
+ expect(response.body).to eq(File.read('spec/fixtures/employee_with_custom_client.html'))
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe "routing to dossier" do
4
+ it "routes /dossier/reports/:report to dossier/reports#show" do
5
+ {:get => '/reports/employee'}.should route_to(
6
+ :controller => 'dossier/reports',
7
+ :action => 'show',
8
+ :report => 'employee'
9
+ )
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ # Configure Rails Environment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rails/test_help"
6
+ require 'rspec/rails'
7
+ require 'pry'
8
+
9
+ Rails.backtrace_cleaner.remove_silencers!
10
+
11
+ # Load support files
12
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
13
+
14
+ DB_CONFIG = [:mysql2, :sqlite3].reduce({}) do |config, adapter_name|
15
+ config.tap do |hash|
16
+ path = "spec/fixtures/db/#{adapter_name}.yml"
17
+ hash[adapter_name] = YAML.load_file(path).symbolize_keys if File.exist?(path)
18
+ end
19
+ end.freeze
20
+
21
+ RSpec.configure do |config|
22
+ config.mock_with :rspec
23
+
24
+ config.before :suite do
25
+ DB_CONFIG.keys.each do |adapter|
26
+ Dossier::Factory.send("#{adapter}_create_employees")
27
+ Dossier::Factory.send("#{adapter}_seed_employees")
28
+ end
29
+ end
30
+
31
+ config.after :each do
32
+ Dossier.instance_variable_set(:@configuration, nil)
33
+ end
34
+
35
+ config.order = :random
36
+ end
@@ -0,0 +1,86 @@
1
+ module Dossier
2
+ module Factory
3
+ extend self
4
+ def employees
5
+ [
6
+ {name: "Moustafa McMann", hired_on: '2010-10-02', suspended: false, division: 'Zany Inventions', salary: 30_000 },
7
+ {name: 'Jimmy Jackalope, Jr.', hired_on: '2013-01-11', suspended: true, division: 'Tedious Toiling', salary: 20_000 },
8
+ {name: 'Elise Elderberry', hired_on: '2013-01-11', suspended: false, division: 'Corporate Malfeasance', salary: 99_000 }
9
+ ]
10
+ end
11
+
12
+ def mysql2_client
13
+ @mysql2_client ||= Dossier::Client.new(DB_CONFIG[:mysql2])
14
+ end
15
+
16
+ def sqlite3_client
17
+ @sqlite3_client ||= Dossier::Client.new(DB_CONFIG[:sqlite3])
18
+ end
19
+
20
+ def mysql2_connection
21
+ mysql2_client.adapter.connection
22
+ end
23
+
24
+ def sqlite3_connection
25
+ sqlite3_client.adapter.connection
26
+ end
27
+
28
+ def mysql2_create_employees
29
+ mysql2_connection.execute('CREATE DATABASE IF NOT EXISTS `dossier_test`', 'FACTORY')
30
+ mysql2_connection.execute('DROP TABLE IF EXISTS `employees`', 'FACTORY')
31
+ mysql2_connection.execute(
32
+ <<-SQL, 'FACTORY'
33
+ CREATE TABLE `employees` (
34
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
35
+ `name` varchar(255) NOT NULL,
36
+ `division` varchar(255) NOT NULL,
37
+ `salary` int(11) NOT NULL,
38
+ `suspended` tinyint(1) NOT NULL DEFAULT 0,
39
+ `hired_on` date NOT NULL,
40
+ PRIMARY KEY (`id`)
41
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
42
+ SQL
43
+ )
44
+ end
45
+
46
+ def sqlite3_create_employees
47
+ sqlite3_connection.execute('DROP TABLE IF EXISTS `employees`', 'FACTORY')
48
+ sqlite3_connection.execute(
49
+ <<-SQL, 'FACTORY'
50
+ CREATE TABLE `employees` (
51
+ `id` INTEGER PRIMARY KEY AUTOINCREMENT,
52
+ `name` TEXT NOT NULL,
53
+ `division` TEXT NOT NULL,
54
+ `salary` INTEGER NOT NULL,
55
+ `suspended` TINYINT NOT NULL DEFAULT 0,
56
+ `hired_on` DATE NOT NULL
57
+ );
58
+ SQL
59
+ )
60
+ end
61
+
62
+ def mysql2_seed_employees
63
+ mysql2_connection.execute('TRUNCATE `employees`', 'FACTORY')
64
+ employees.each do |employee|
65
+ query = <<-QUERY
66
+ INSERT INTO
67
+ `employees` (`name`, `hired_on`, `suspended`, `division`, `salary`)
68
+ VALUES ('#{employee[:name]}', '#{employee[:hired_on]}', #{employee[:suspended]}, '#{employee[:division]}', #{employee[:salary]});
69
+ QUERY
70
+ mysql2_connection.execute(query, 'FACTORY')
71
+ end
72
+ end
73
+
74
+ def sqlite3_seed_employees
75
+ sqlite3_connection.execute('DELETE FROM `employees`', 'FACTORY')
76
+ employees.each do |employee|
77
+ query = <<-QUERY
78
+ INSERT INTO
79
+ `employees` (`name`, `hired_on`, `suspended`, `division`, `salary`)
80
+ VALUES ('#{employee[:name].upcase}', '#{employee[:hired_on]}', #{employee[:suspended] ? 1 : 0}, '#{employee[:division]}', #{employee[:salary]});
81
+ QUERY
82
+ sqlite3_connection.execute(query, 'FACTORY')
83
+ end
84
+ end
85
+ end
86
+ end