bisque 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +65 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +108 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/bisque.gemspec +84 -0
- data/lib/bisque/exceptions.rb +4 -0
- data/lib/bisque/report.rb +146 -0
- data/lib/bisque/report_row.rb +12 -0
- data/lib/bisque.rb +6 -0
- data/spec/bisque/exceptions_spec.rb +14 -0
- data/spec/bisque/report_row_spec.rb +64 -0
- data/spec/bisque/report_spec.rb +181 -0
- data/spec/bisque_spec.rb +16 -0
- data/spec/resources/models.rb +46 -0
- data/spec/resources/schema.rb +15 -0
- data/spec/spec_helper.rb +63 -0
- metadata +172 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.3@bisque
|
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
gem 'activerecord', '>= 3.0.0'
|
6
|
+
gem 'pg'
|
7
|
+
|
8
|
+
# Add dependencies to develop your gem here.
|
9
|
+
# Include everything needed to run rake, tests, features, etc.
|
10
|
+
group :development do
|
11
|
+
gem "rspec", "~> 2.8.0"
|
12
|
+
gem "rdoc", "~> 3.12"
|
13
|
+
gem "bundler", "~> 1.1.0"
|
14
|
+
gem "jeweler", "~> 1.8.4"
|
15
|
+
gem "simplecov", ">= 0"
|
16
|
+
gem 'spork'
|
17
|
+
gem 'pry'
|
18
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activemodel (3.2.8)
|
5
|
+
activesupport (= 3.2.8)
|
6
|
+
builder (~> 3.0.0)
|
7
|
+
activerecord (3.2.8)
|
8
|
+
activemodel (= 3.2.8)
|
9
|
+
activesupport (= 3.2.8)
|
10
|
+
arel (~> 3.0.2)
|
11
|
+
tzinfo (~> 0.3.29)
|
12
|
+
activesupport (3.2.8)
|
13
|
+
i18n (~> 0.6)
|
14
|
+
multi_json (~> 1.0)
|
15
|
+
arel (3.0.2)
|
16
|
+
builder (3.0.0)
|
17
|
+
coderay (1.0.7)
|
18
|
+
diff-lcs (1.1.3)
|
19
|
+
git (1.2.5)
|
20
|
+
i18n (0.6.0)
|
21
|
+
jeweler (1.8.4)
|
22
|
+
bundler (~> 1.0)
|
23
|
+
git (>= 1.2.5)
|
24
|
+
rake
|
25
|
+
rdoc
|
26
|
+
json (1.7.5)
|
27
|
+
method_source (0.8)
|
28
|
+
multi_json (1.3.6)
|
29
|
+
pg (0.14.0)
|
30
|
+
pry (0.9.10)
|
31
|
+
coderay (~> 1.0.5)
|
32
|
+
method_source (~> 0.8)
|
33
|
+
slop (~> 3.3.1)
|
34
|
+
rake (0.9.2.2)
|
35
|
+
rdoc (3.12)
|
36
|
+
json (~> 1.4)
|
37
|
+
rspec (2.8.0)
|
38
|
+
rspec-core (~> 2.8.0)
|
39
|
+
rspec-expectations (~> 2.8.0)
|
40
|
+
rspec-mocks (~> 2.8.0)
|
41
|
+
rspec-core (2.8.0)
|
42
|
+
rspec-expectations (2.8.0)
|
43
|
+
diff-lcs (~> 1.1.2)
|
44
|
+
rspec-mocks (2.8.0)
|
45
|
+
simplecov (0.6.4)
|
46
|
+
multi_json (~> 1.0)
|
47
|
+
simplecov-html (~> 0.5.3)
|
48
|
+
simplecov-html (0.5.3)
|
49
|
+
slop (3.3.3)
|
50
|
+
spork (0.9.2)
|
51
|
+
tzinfo (0.3.33)
|
52
|
+
|
53
|
+
PLATFORMS
|
54
|
+
ruby
|
55
|
+
|
56
|
+
DEPENDENCIES
|
57
|
+
activerecord (>= 3.0.0)
|
58
|
+
bundler (~> 1.1.0)
|
59
|
+
jeweler (~> 1.8.4)
|
60
|
+
pg
|
61
|
+
pry
|
62
|
+
rdoc (~> 3.12)
|
63
|
+
rspec (~> 2.8.0)
|
64
|
+
simplecov
|
65
|
+
spork
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Jeremy Holland
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
= bisque
|
2
|
+
|
3
|
+
Bisque is meant to ease the pain of "reporting"-style ad-hoc SQL queries in ActiveRecord. Most of the time, I see (and am guilty of having executed myself) solutions to this problem in one of two styles:
|
4
|
+
|
5
|
+
== Fugly: New scopes / class methods / find_by_sql
|
6
|
+
|
7
|
+
*Example*:
|
8
|
+
|
9
|
+
class HooHah < ActiveRecord::Base
|
10
|
+
scope :some_ridiculous_reporting_query, select(<<-RUBY
|
11
|
+
MOFO_OBSCURE_SQL_FUNCTION(some_table.some_column) AS some_non_column_field
|
12
|
+
RUBY
|
13
|
+
).joins(<<-RUBY
|
14
|
+
INNER JOIN god_knows_what ON some_computationally_difficult_calculation = 5
|
15
|
+
RUBY
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
*Pros*: You get to use the existing ActiveRecord::Base hot mustard to execute your queries, parse them to fields on instances of the class, and handle them as collections
|
20
|
+
|
21
|
+
*Cons*: Your reports are ultimately instances of some model - but most reports are not that at all! They're aggregate views over your models, and trying to cram them into existing instances forces you to conflate two very distinct concepts in the domain.
|
22
|
+
|
23
|
+
== Even Fuglier: Query straight from the connection, then use the raw result or OpenStruct it in order to achieve some measure of separation
|
24
|
+
|
25
|
+
*Example*:
|
26
|
+
|
27
|
+
results = ActiveRecord::Base.connection.execute <<-RUBY
|
28
|
+
SELECT MOFO_OBSCURE_SQL_FUNCTION(some_table.some_column) AS some_non_column_field FROM umpteen_thousand_tables
|
29
|
+
INNER JOIN god_knows_what ON some_computationally_difficult_calculation = 5
|
30
|
+
RUBY
|
31
|
+
|
32
|
+
results.each do |row|
|
33
|
+
#ARGGHH
|
34
|
+
end
|
35
|
+
|
36
|
+
*Pros*: Avoids the conflation of the report with models it doesn't represent
|
37
|
+
*Cons*: Pretty much everything else. Lots of boilerplate.
|
38
|
+
|
39
|
+
== Help Arrives!
|
40
|
+
|
41
|
+
Enter Bisque. Bisque provides a simple way of defining Report classes, each with its own query and designated parameters, as well as a way to dynamically define methods on its rows. Bisque will translate any returned datatypes into their AR analog, and in general help you keep your jazz organized and tight. Here's how to use it:
|
42
|
+
|
43
|
+
=== Step 1: Define a report class
|
44
|
+
|
45
|
+
Reports inherit from Bisque::Report, and have the following API:
|
46
|
+
|
47
|
+
class FooReport < Bisque::Report
|
48
|
+
query <<-RUBY
|
49
|
+
SELECT
|
50
|
+
SUM(o.total) AS total,
|
51
|
+
MEAN(o.total) AS average
|
52
|
+
FROM
|
53
|
+
orders o
|
54
|
+
INNER JOIN
|
55
|
+
customers c ON c.id = o.customer_id
|
56
|
+
WHERE
|
57
|
+
o.store_type = :store_type
|
58
|
+
AND
|
59
|
+
c.id = :customer_id
|
60
|
+
RUBY
|
61
|
+
|
62
|
+
defaults :store_type => "digital"
|
63
|
+
|
64
|
+
rows do
|
65
|
+
def total_in_cents
|
66
|
+
total*100
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
==== Bisque::Report.query
|
72
|
+
Every report *must* have a query. Define it here, using colon-prefixed words to designate parameters
|
73
|
+
|
74
|
+
==== Bisque::Report.defaults
|
75
|
+
This method takes a hash of defaults, if any, for the parameters in your query. Each parameter must either have some default set for it, or be passed a value at runtime (see instantiatino below)
|
76
|
+
|
77
|
+
==== Bisque::Report.rows
|
78
|
+
If you wish to define custom methods on each individual row item of the report, define them here, and they will be evaluated in the context of the dynamically generated row class (which will be namespaced the same as the report class and named <YourReportClassName>Row).
|
79
|
+
|
80
|
+
=== Step 2: Instantiate the report
|
81
|
+
To use run a given report, just create a new instance of it. Each report instance is enumerable and so may be iterated over as usual.
|
82
|
+
|
83
|
+
report = FooReport.new :customer_id => 42
|
84
|
+
|
85
|
+
You must provide a hash of values for each parameter (that doesn't have a default) defined in the query, or a Bisque::MissingParameterException will be raised and the report will not be executed.
|
86
|
+
|
87
|
+
If you have defined any custom row methods (via the rows block discussed above), you may call them on each item of the iterator as one would expect:
|
88
|
+
|
89
|
+
puts report.first.total_in_cents
|
90
|
+
|
91
|
+
== In closing
|
92
|
+
For the time being, Bisque supports PostgreSQL exclusively (db-agnositicism is broken due to the necessities associated with typecasting dynamically selected values), because I virtually never use anything else and wanted this gem out there ASAP for my own purposes. I sincerely doubt I'll ever get around to extending it for support of other AR-supported dbs, but if one of you fine folks would like to do so, submit a pull request as described below and I'll happily include it. Of course, any other improvements, feature requests, etc. will be considered and taken into account - I would like to see this grow into a highly versatile tool, so suggest away!
|
93
|
+
|
94
|
+
== Contributing to bisque
|
95
|
+
|
96
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
97
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
98
|
+
* Fork the project.
|
99
|
+
* Start a feature/bugfix branch.
|
100
|
+
* Commit and push until you are happy with your contribution.
|
101
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
102
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
103
|
+
|
104
|
+
== Copyright
|
105
|
+
|
106
|
+
Copyright (c) 2012 Jeremy Holland. See LICENSE.txt for
|
107
|
+
further details.
|
108
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "bisque"
|
18
|
+
gem.homepage = "http://github.com/awebneck/bisque"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{A simple gem for ease of use in generating reports with ActiveRecord}
|
21
|
+
gem.description = %Q{Bisque exists to ease the organizational pain of having to attach reporting and ad-hoc queries to ActiveRecord models in order to get any class-like behavior out of them by providing a new class and DSL for that express purpose.}
|
22
|
+
gem.email = "jeremy@jeremypholland.com"
|
23
|
+
gem.authors = ["Jeremy Holland"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
require 'rdoc/task'
|
42
|
+
Rake::RDocTask.new do |rdoc|
|
43
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "bisque #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bisque.gemspec
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "bisque"
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jeremy Holland"]
|
12
|
+
s.date = "2012-09-01"
|
13
|
+
s.description = "Bisque exists to ease the organizational pain of having to attach reporting and ad-hoc queries to ActiveRecord models in order to get any class-like behavior out of them by providing a new class and DSL for that express purpose."
|
14
|
+
s.email = "jeremy@jeremypholland.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
".rvmrc",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"bisque.gemspec",
|
30
|
+
"lib/bisque.rb",
|
31
|
+
"lib/bisque/exceptions.rb",
|
32
|
+
"lib/bisque/report.rb",
|
33
|
+
"lib/bisque/report_row.rb",
|
34
|
+
"spec/bisque/exceptions_spec.rb",
|
35
|
+
"spec/bisque/report_row_spec.rb",
|
36
|
+
"spec/bisque/report_spec.rb",
|
37
|
+
"spec/bisque_spec.rb",
|
38
|
+
"spec/resources/models.rb",
|
39
|
+
"spec/resources/schema.rb",
|
40
|
+
"spec/spec_helper.rb"
|
41
|
+
]
|
42
|
+
s.homepage = "http://github.com/awebneck/bisque"
|
43
|
+
s.licenses = ["MIT"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = "1.8.15"
|
46
|
+
s.summary = "A simple gem for ease of use in generating reports with ActiveRecord"
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
s.specification_version = 3
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0"])
|
53
|
+
s.add_runtime_dependency(%q<pg>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
55
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
56
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.1.0"])
|
57
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
58
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
59
|
+
s.add_development_dependency(%q<spork>, [">= 0"])
|
60
|
+
s.add_development_dependency(%q<pry>, [">= 0"])
|
61
|
+
else
|
62
|
+
s.add_dependency(%q<activerecord>, [">= 3.0.0"])
|
63
|
+
s.add_dependency(%q<pg>, [">= 0"])
|
64
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
65
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
66
|
+
s.add_dependency(%q<bundler>, ["~> 1.1.0"])
|
67
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
68
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
69
|
+
s.add_dependency(%q<spork>, [">= 0"])
|
70
|
+
s.add_dependency(%q<pry>, [">= 0"])
|
71
|
+
end
|
72
|
+
else
|
73
|
+
s.add_dependency(%q<activerecord>, [">= 3.0.0"])
|
74
|
+
s.add_dependency(%q<pg>, [">= 0"])
|
75
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
76
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
77
|
+
s.add_dependency(%q<bundler>, ["~> 1.1.0"])
|
78
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
79
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
80
|
+
s.add_dependency(%q<spork>, [">= 0"])
|
81
|
+
s.add_dependency(%q<pry>, [">= 0"])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
@@ -0,0 +1,146 @@
|
|
1
|
+
module Bisque
|
2
|
+
class Report
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_accessor :params, :sql
|
6
|
+
|
7
|
+
def initialize(params={})
|
8
|
+
@params = self.class.defaults.merge params
|
9
|
+
@sql = self.class.query.dup
|
10
|
+
self.class.params.each do |param|
|
11
|
+
value = @params[param]
|
12
|
+
raise Bisque::MissingParameterException, "Missing parameter :#{param} for construction of #{self.class} - please provide a value for this parameter to the constructor or define a default." if value.nil?
|
13
|
+
@sql.gsub!(/:#{param}/, sanitize_and_sqlize(value))
|
14
|
+
end
|
15
|
+
@results = ActiveRecord::Base.connection.execute @sql
|
16
|
+
extract_datatypes
|
17
|
+
construct_converted
|
18
|
+
end
|
19
|
+
|
20
|
+
def each
|
21
|
+
if block_given?
|
22
|
+
@converted.each do |r|
|
23
|
+
yield r
|
24
|
+
end
|
25
|
+
else
|
26
|
+
Enumerator.new self, :each
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def [](index)
|
31
|
+
@converted[index]
|
32
|
+
end
|
33
|
+
|
34
|
+
def last
|
35
|
+
@converted.last
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
"#{self.class}: #{count} result#{'s' if count != 1}"
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
def sanitize_and_sqlize(value)
|
44
|
+
if value.is_a? Array
|
45
|
+
"(#{value.map { |v| sanitize_and_sqlize(v) }.join(",")})"
|
46
|
+
else
|
47
|
+
ActiveRecord::Base.connection.quote(value)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def extract_datatypes
|
52
|
+
sql = "SELECT"
|
53
|
+
@results.fields.each_with_index do |f, i|
|
54
|
+
sql << " UNION SELECT" if i > 0
|
55
|
+
sql << " format_type(#{@results.ftype(i)}, #{@results.fmod(i)}) AS type, #{ActiveRecord::Base.sanitize(f)} AS key"
|
56
|
+
end
|
57
|
+
typeresults = ActiveRecord::Base.connection.execute(sql)
|
58
|
+
@types = {}
|
59
|
+
typeresults.to_a.each do |typeresult|
|
60
|
+
@types[typeresult['key'].intern] = typeresult['type']
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def construct_converted
|
65
|
+
@converted = []
|
66
|
+
@results.to_a.each do |r|
|
67
|
+
@converted << self.class.row_class.new( r.merge(r) { |k, v| convert_value(k,v) })
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def convert_value(key, value)
|
72
|
+
return value if value.nil?
|
73
|
+
case @types[key.intern]
|
74
|
+
when /integer/
|
75
|
+
value.to_i
|
76
|
+
when /decimal/
|
77
|
+
value.to_f
|
78
|
+
when /float/
|
79
|
+
value.to_f
|
80
|
+
when /numeric/
|
81
|
+
value.to_f
|
82
|
+
when /precision/
|
83
|
+
value.to_f
|
84
|
+
when /boolean/
|
85
|
+
value == 't'
|
86
|
+
when /date/
|
87
|
+
Date.parse value
|
88
|
+
when /timestamp/
|
89
|
+
Time.parse value
|
90
|
+
when /bytea/
|
91
|
+
ActiveRecord::Base.connection.unescape_bytea(value)
|
92
|
+
else
|
93
|
+
value.to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class << self
|
98
|
+
def default(key, val)
|
99
|
+
@defaults ||= {}
|
100
|
+
@defaults[key] = val
|
101
|
+
end
|
102
|
+
|
103
|
+
def defaults(hash=nil)
|
104
|
+
if hash
|
105
|
+
@defaults ||= {}
|
106
|
+
@defaults.merge! hash
|
107
|
+
else
|
108
|
+
@defaults || {}
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def query(qstr=nil)
|
113
|
+
if qstr
|
114
|
+
@qstr = qstr.strip
|
115
|
+
@params = qstr.scan(/:\w+/).map { |p| p.gsub(/:/,'').intern }
|
116
|
+
else
|
117
|
+
raise Bisque::MissingQueryException, "Bisque Report #{self} missing query definition." if @qstr.nil?
|
118
|
+
@qstr
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def rows(&block)
|
123
|
+
if block_given?
|
124
|
+
carray = self.to_s.split(/::/)
|
125
|
+
carray.last << 'Row'
|
126
|
+
@row_class = carray.join('::')
|
127
|
+
c = Class.new(Bisque::ReportRow)
|
128
|
+
c.class_eval(&block)
|
129
|
+
Object.const_set @row_class, c
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def row_class
|
134
|
+
return Bisque::ReportRow if @row_class.nil?
|
135
|
+
names = @row_class.split('::')
|
136
|
+
names.reduce(Object) do |mod, name|
|
137
|
+
mod.const_defined?(name) ? mod.const_get(name) : mod.const_missing(name)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def params
|
142
|
+
@params || []
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/bisque.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Bisque Exceptions" do
|
4
|
+
describe Bisque::MissingQueryException do
|
5
|
+
it "should be an Exception" do
|
6
|
+
Bisque::MissingQueryException.ancestors.should include Exception
|
7
|
+
end
|
8
|
+
end
|
9
|
+
describe Bisque::MissingParameterException do
|
10
|
+
it "should be an Exception" do
|
11
|
+
Bisque::MissingQueryException.ancestors.should include Exception
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Bisque::ReportRow do
|
4
|
+
before :all do
|
5
|
+
Frobnitz.create :name => 'Howdy',
|
6
|
+
:description => 'Here is some text',
|
7
|
+
:score => 12,
|
8
|
+
:cost => 48.22,
|
9
|
+
:numberish => Math::PI,
|
10
|
+
:timish => Time.now - (60*60*24*3),
|
11
|
+
:summed_at => Time.now + (60*60*24*3),
|
12
|
+
:created_on => Date.new(2012),
|
13
|
+
:boolish => true,
|
14
|
+
:binny => "\x00\x01\x02\x03"
|
15
|
+
Frobnitz.create :name => 'Slam',
|
16
|
+
:description => 'Here is some other text',
|
17
|
+
:score => 8,
|
18
|
+
:cost => 12.53,
|
19
|
+
:numberish => Math::E,
|
20
|
+
:timish => Time.now + (60*60*24*3),
|
21
|
+
:summed_at => Time.now - (60*60*24*3),
|
22
|
+
:created_on => Date.new(2011),
|
23
|
+
:boolish => false,
|
24
|
+
:binny => "\x03\x02\x01\x00"
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "construction" do
|
28
|
+
it "should be an instance of Bisque::ReportRow if the rows block is undefined" do
|
29
|
+
f = FooReport.new
|
30
|
+
f.first.should be_a Bisque::ReportRow
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should be an instance of the dynamically created Row class if the rows block is defined" do
|
34
|
+
f = FooeyReport.new :corn => 'hat'
|
35
|
+
f.first.should be_a FooeyReportRow
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "instance methods" do
|
40
|
+
it "should provide an accessor method for each field in the report" do
|
41
|
+
f = FooReport.new
|
42
|
+
r = f.first
|
43
|
+
r.name.should == 'Howdy'
|
44
|
+
r.description.should == 'Here is some text'
|
45
|
+
r.score.should == 12
|
46
|
+
r.cost.should == 48.22
|
47
|
+
((Math::PI - r.numberish).abs < 0.001).should == true
|
48
|
+
r.timish.should_not be_nil
|
49
|
+
r.summed_at.should_not be_nil
|
50
|
+
r.created_on.should_not be_nil
|
51
|
+
r.boolish.should == true
|
52
|
+
r.binny.should == "\x00\x01\x02\x03"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should respond to calls defined in the rows block" do
|
56
|
+
f = FooeyReport.new :corn => 'hat'
|
57
|
+
f.first.whoop.should == 'silly'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
after(:all) do
|
62
|
+
Frobnitz.destroy_all
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Bisque::Report do
|
4
|
+
describe "class methods" do
|
5
|
+
describe "query" do
|
6
|
+
it "should return the query specified in the class" do
|
7
|
+
FooReport.query.should == "SELECT * FROM frobnitzs"
|
8
|
+
BarReport.query.should == "SELECT * FROM frobnitzs WHERE name = :corn"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should raise a Bisque::MissingQueryException if no query is defined" do
|
12
|
+
lambda { NoQueryReport.query }.should raise_error Bisque::MissingQueryException
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "params" do
|
17
|
+
it "should return an empty array if no parameters exist" do
|
18
|
+
FooReport.params.should be_a Array
|
19
|
+
FooReport.params.should be_empty
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return a list of the parameters extracted from the query if present" do
|
23
|
+
FooReport.params.should be_a Array
|
24
|
+
BarReport.params.length.should == 1
|
25
|
+
BarReport.params.should include :corn
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "defaults" do
|
30
|
+
it "should return an empty hash if no defaults exist" do
|
31
|
+
BarReport.defaults.should be_a Hash
|
32
|
+
BarReport.defaults.should be_empty
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return an empty hash of default values specified by the defaults class method" do
|
36
|
+
BazReport.defaults.should be_a Hash
|
37
|
+
BazReport.defaults[:corn].should == 'hat'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return an empty hash of default values specified by the default class method" do
|
41
|
+
QuuxReport.defaults.should be_a Hash
|
42
|
+
QuuxReport.defaults[:slip].should == 'paper'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "row_class" do
|
47
|
+
it "should return Bisque::ReportRow if no rows block is defined" do
|
48
|
+
FooReport.row_class.should == Bisque::ReportRow
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return the dynamic class defined by the report's class if a rows block is defined" do
|
52
|
+
FunReport.row_class.should == FunReportRow
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "behaviors" do
|
58
|
+
it "should be Enumerable" do
|
59
|
+
FooReport.should include Enumerable
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "instance methods" do
|
64
|
+
before :all do
|
65
|
+
Frobnitz.create :name => 'Howdy',
|
66
|
+
:description => 'Here is some text',
|
67
|
+
:score => 12,
|
68
|
+
:cost => 48.22,
|
69
|
+
:numberish => Math::PI,
|
70
|
+
:timish => Time.now - (60*60*24*3),
|
71
|
+
:summed_at => Time.now + (60*60*24*3),
|
72
|
+
:created_on => Date.new(2012),
|
73
|
+
:boolish => true,
|
74
|
+
:binny => "\x00\x01\x02\x03"
|
75
|
+
Frobnitz.create :name => 'Slam',
|
76
|
+
:description => 'Here is some other text',
|
77
|
+
:score => 8,
|
78
|
+
:cost => 12.53,
|
79
|
+
:numberish => Math::E,
|
80
|
+
:timish => Time.now + (60*60*24*3),
|
81
|
+
:summed_at => Time.now - (60*60*24*3),
|
82
|
+
:created_on => Date.new(2011),
|
83
|
+
:boolish => false,
|
84
|
+
:binny => "\x03\x02\x01\x00"
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "construction" do
|
88
|
+
it "should be constructable with no arguments if the query designates no parameters" do
|
89
|
+
lambda { FooReport.new }.should_not raise_error
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should be constructable with no arguments if the query designates parameters and defaults therefor" do
|
93
|
+
lambda { BazReport.new }.should_not raise_error
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should raise a Bisque::MissingParameterException if the query designates parameters but no defaults, and it is constructed with no arguments" do
|
97
|
+
lambda { BarReport.new }.should raise_error Bisque::MissingParameterException
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should accept a hash of parameters" do
|
101
|
+
lambda { BarReport.new :corn => 'cheese' }.should_not raise_error
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "to_s" do
|
106
|
+
it "should return the name of the class and a count of resulting rows" do
|
107
|
+
f = FooReport.new
|
108
|
+
f.to_s.should == 'FooReport: 2 results'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "each" do
|
113
|
+
it "should return an enumerator of the results if called without a block" do
|
114
|
+
f = FooReport.new
|
115
|
+
e = f.each
|
116
|
+
e.should be_a Enumerator
|
117
|
+
e.count.should == 2
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should loop over the results, passing each result to the block if called with a block" do
|
121
|
+
f = FooReport.new
|
122
|
+
i = 0
|
123
|
+
f.each do |r|
|
124
|
+
i += 1
|
125
|
+
end
|
126
|
+
i.should == 2
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "[]" do
|
131
|
+
it "should allow array access to the results" do
|
132
|
+
f = FooReport.new
|
133
|
+
f[0].should be_a Bisque::ReportRow
|
134
|
+
f[1].should be_a Bisque::ReportRow
|
135
|
+
f[0].should_not == f[1]
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "last" do
|
140
|
+
it "should return the last result" do
|
141
|
+
f = FooReport.new
|
142
|
+
f.last.should == f[1]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "params" do
|
147
|
+
it "should return the hash of specified parameters if there are no defaults" do
|
148
|
+
b = BarReport.new :corn => 'chili'
|
149
|
+
b.params.should == {:corn => 'chili'}
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should return the hash of defaults overridden with specified parameters if defaults are defind" do
|
153
|
+
b = BazReport.new
|
154
|
+
b.params.should == {:corn => 'hat'}
|
155
|
+
b = BazReport.new :corn => 'powder'
|
156
|
+
b.params.should == {:corn => 'powder'}
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "sql" do
|
161
|
+
it "should return the report's query with the parameters interpolated thereto" do
|
162
|
+
p = ParamReport.new :name => 'test',
|
163
|
+
:description => 'testagain',
|
164
|
+
:score => 12,
|
165
|
+
:cost => 34.12,
|
166
|
+
:numberish => 123.35583,
|
167
|
+
:created_at => Time.new(2012,1,1,5,0,0),
|
168
|
+
:timish => Time.new(2012,1,1,6,0,0),
|
169
|
+
:summed_at => Time.new(2012,1,1,7,0,0),
|
170
|
+
:created_on => Date.new(2012,2,1),
|
171
|
+
:boolish => true,
|
172
|
+
:binny => "\x00\x01\x02\x03"
|
173
|
+
p.sql.should == "SELECT * FROM frobnitzs WHERE name = 'test' AND description = 'testagain' AND score = 12 AND cost = 34.12 AND numberish = 123.35583 AND created_at = '2012-01-01 05:00:00.000000' AND timish = '2012-01-01 06:00:00.000000' AND summed_at = '2012-01-01 07:00:00.000000' AND created_on = '2012-02-01' AND boolish = 't' AND binny = ''"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
after(:all) do
|
178
|
+
Frobnitz.destroy_all
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
data/spec/bisque_spec.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Bisque do
|
4
|
+
it "should define the Bisque::Report class" do
|
5
|
+
lambda { Bisque::Report }.should_not raise_error
|
6
|
+
end
|
7
|
+
it "should define the Bisque::ReportRow class" do
|
8
|
+
lambda { Bisque::ReportRow }.should_not raise_error
|
9
|
+
end
|
10
|
+
it "should define the Bisque::MissingQueryException class" do
|
11
|
+
lambda { Bisque::MissingQueryException }.should_not raise_error
|
12
|
+
end
|
13
|
+
it "should define the Bisque::MissingParameterException class" do
|
14
|
+
lambda { Bisque::MissingParameterException }.should_not raise_error
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Frobnitz < ActiveRecord::Base
|
2
|
+
end
|
3
|
+
|
4
|
+
class NoQueryReport < Bisque::Report
|
5
|
+
end
|
6
|
+
|
7
|
+
class FooReport < Bisque::Report
|
8
|
+
query "SELECT * FROM frobnitzs"
|
9
|
+
end
|
10
|
+
|
11
|
+
class FooeyReport < Bisque::Report
|
12
|
+
query "SELECT * FROM frobnitzs"
|
13
|
+
rows do
|
14
|
+
def whoop
|
15
|
+
'silly'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class BarReport < Bisque::Report
|
21
|
+
query "SELECT * FROM frobnitzs WHERE name = :corn"
|
22
|
+
end
|
23
|
+
|
24
|
+
class BazReport < Bisque::Report
|
25
|
+
query "SELECT * FROM frobnitzs WHERE name = :corn"
|
26
|
+
defaults :corn => 'hat'
|
27
|
+
end
|
28
|
+
|
29
|
+
class QuuxReport < Bisque::Report
|
30
|
+
query "SELECT * FROM frobnitzs WHERE name = :corn"
|
31
|
+
default :slip, 'paper'
|
32
|
+
end
|
33
|
+
|
34
|
+
class FunReport < Bisque::Report
|
35
|
+
query "SELECT * FROM frobnitzs WHERE name = :corn"
|
36
|
+
default :slip, 'paper'
|
37
|
+
rows do
|
38
|
+
def whoop
|
39
|
+
'silly'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class ParamReport < Bisque::Report
|
45
|
+
query "SELECT * FROM frobnitzs WHERE name = :name AND description = :description AND score = :score AND cost = :cost AND numberish = :numberish AND created_at = :created_at AND timish = :timish AND summed_at = :summed_at AND created_on = :created_on AND boolish = :boolish AND binny = :binny"
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table :frobnitzs, :force => true do |t|
|
3
|
+
t.column :name, :string
|
4
|
+
t.column :description, :text
|
5
|
+
t.column :score, :integer
|
6
|
+
t.column :cost, :decimal, :precision => 5, :scale => 2
|
7
|
+
t.column :numberish, :float
|
8
|
+
t.column :created_at, :datetime
|
9
|
+
t.column :timish, :timestamp
|
10
|
+
t.column :summed_at, :time
|
11
|
+
t.column :created_on, :date
|
12
|
+
t.column :boolish, :boolean
|
13
|
+
t.column :binny, :binary
|
14
|
+
end
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'active_record'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'bisque'
|
7
|
+
require 'pry'
|
8
|
+
|
9
|
+
DB_USER = 'bisque'
|
10
|
+
DB_PASS = 'bisquepass1234'
|
11
|
+
|
12
|
+
# Requires supporting files with custom matchers and macros, etc,
|
13
|
+
# in ./support/ and its subdirectories.
|
14
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
15
|
+
|
16
|
+
def stfu
|
17
|
+
begin
|
18
|
+
orig_stderr = $stderr.clone
|
19
|
+
orig_stdout = $stdout.clone
|
20
|
+
$stderr.reopen File.new('/dev/null', 'w')
|
21
|
+
$stdout.reopen File.new('/dev/null', 'w')
|
22
|
+
retval = yield
|
23
|
+
rescue Exception => e
|
24
|
+
$stdout.reopen orig_stdout
|
25
|
+
$stderr.reopen orig_stderr
|
26
|
+
raise e
|
27
|
+
ensure
|
28
|
+
$stdout.reopen orig_stdout
|
29
|
+
$stderr.reopen orig_stderr
|
30
|
+
end
|
31
|
+
retval
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec.configure do |config|
|
35
|
+
dir = File.dirname(__FILE__)
|
36
|
+
dbconfig = {
|
37
|
+
'adapter' => 'postgresql',
|
38
|
+
'encoding' => 'unicode',
|
39
|
+
'database' => 'bisque_development',
|
40
|
+
'pool' => 5,
|
41
|
+
'username' => DB_USER,
|
42
|
+
'password' => DB_PASS}
|
43
|
+
|
44
|
+
config.before(:all) do
|
45
|
+
ENV["RAILS_ENV"] ||= "test"
|
46
|
+
ActiveRecord::Base.establish_connection dbconfig.merge 'database' => 'postgres', 'schema_search_path' => 'public'
|
47
|
+
ActiveRecord::Base.connection.create_database dbconfig['database'], dbconfig
|
48
|
+
ActiveRecord::Base.remove_connection
|
49
|
+
ActiveRecord::Base.configurations = {'test' => dbconfig}
|
50
|
+
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
|
51
|
+
ActiveRecord::Migration.verbose = false
|
52
|
+
stfu do
|
53
|
+
load "#{dir}/resources/schema.rb"
|
54
|
+
load "#{dir}/resources/models.rb"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
config.after(:all) do
|
59
|
+
ActiveRecord::Base.remove_connection
|
60
|
+
ActiveRecord::Base.establish_connection dbconfig.merge 'database' => 'postgres', 'schema_search_path' => 'public'
|
61
|
+
ActiveRecord::Base.connection.drop_database dbconfig['database']
|
62
|
+
end
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bisque
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jeremy Holland
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: &11122500 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *11122500
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: pg
|
27
|
+
requirement: &11120660 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *11120660
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &11118060 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.8.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *11118060
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rdoc
|
49
|
+
requirement: &11115660 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.12'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *11115660
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: bundler
|
60
|
+
requirement: &11552740 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.1.0
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *11552740
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jeweler
|
71
|
+
requirement: &11546320 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.8.4
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *11546320
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: simplecov
|
82
|
+
requirement: &11036180 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *11036180
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: spork
|
93
|
+
requirement: &11035140 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *11035140
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: pry
|
104
|
+
requirement: &11032380 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *11032380
|
113
|
+
description: Bisque exists to ease the organizational pain of having to attach reporting
|
114
|
+
and ad-hoc queries to ActiveRecord models in order to get any class-like behavior
|
115
|
+
out of them by providing a new class and DSL for that express purpose.
|
116
|
+
email: jeremy@jeremypholland.com
|
117
|
+
executables: []
|
118
|
+
extensions: []
|
119
|
+
extra_rdoc_files:
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.rdoc
|
122
|
+
files:
|
123
|
+
- .document
|
124
|
+
- .rspec
|
125
|
+
- .rvmrc
|
126
|
+
- Gemfile
|
127
|
+
- Gemfile.lock
|
128
|
+
- LICENSE.txt
|
129
|
+
- README.rdoc
|
130
|
+
- Rakefile
|
131
|
+
- VERSION
|
132
|
+
- bisque.gemspec
|
133
|
+
- lib/bisque.rb
|
134
|
+
- lib/bisque/exceptions.rb
|
135
|
+
- lib/bisque/report.rb
|
136
|
+
- lib/bisque/report_row.rb
|
137
|
+
- spec/bisque/exceptions_spec.rb
|
138
|
+
- spec/bisque/report_row_spec.rb
|
139
|
+
- spec/bisque/report_spec.rb
|
140
|
+
- spec/bisque_spec.rb
|
141
|
+
- spec/resources/models.rb
|
142
|
+
- spec/resources/schema.rb
|
143
|
+
- spec/spec_helper.rb
|
144
|
+
homepage: http://github.com/awebneck/bisque
|
145
|
+
licenses:
|
146
|
+
- MIT
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options: []
|
149
|
+
require_paths:
|
150
|
+
- lib
|
151
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
152
|
+
none: false
|
153
|
+
requirements:
|
154
|
+
- - ! '>='
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
segments:
|
158
|
+
- 0
|
159
|
+
hash: -468949534080404133
|
160
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
requirements: []
|
167
|
+
rubyforge_project:
|
168
|
+
rubygems_version: 1.8.15
|
169
|
+
signing_key:
|
170
|
+
specification_version: 3
|
171
|
+
summary: A simple gem for ease of use in generating reports with ActiveRecord
|
172
|
+
test_files: []
|