schema_plus_views 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +18 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +160 -0
- data/Rakefile +9 -0
- data/gemfiles/Gemfile.base +4 -0
- data/gemfiles/activerecord-4.2/Gemfile.base +3 -0
- data/gemfiles/activerecord-4.2/Gemfile.mysql2 +10 -0
- data/gemfiles/activerecord-4.2/Gemfile.postgresql +10 -0
- data/gemfiles/activerecord-4.2/Gemfile.sqlite3 +10 -0
- data/lib/schema_plus/views/active_record/connection_adapters/abstract_adapter.rb +40 -0
- data/lib/schema_plus/views/active_record/connection_adapters/mysql2_adapter.rb +30 -0
- data/lib/schema_plus/views/active_record/connection_adapters/postgresql_adapter.rb +31 -0
- data/lib/schema_plus/views/active_record/connection_adapters/sqlite3_adapter.rb +18 -0
- data/lib/schema_plus/views/middleware.rb +49 -0
- data/lib/schema_plus/views/version.rb +5 -0
- data/lib/schema_plus/views.rb +22 -0
- data/lib/schema_plus_views.rb +1 -0
- data/schema_dev.yml +8 -0
- data/schema_plus_views.gemspec +29 -0
- data/spec/named_schemas_spec.rb +97 -0
- data/spec/sanity_spec.rb +13 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/views_spec.rb +194 -0
- metadata +185 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 94cd524efd83a80577764570786aa30b828218b4
|
4
|
+
data.tar.gz: e86c50e980bd4e483caea91b6ab00f787a0f7425
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 56febaf08947bed4af3cb7efd7c45a5ccd465f2c8204d71facd52ccea83147342a3ef62cd5cb7a491d9e33a8a7e6c363d6abd418c5513bb7e42f76289dc460ad
|
7
|
+
data.tar.gz: 562f3fbf5c349ee0373948e8e1186d713ef91c90754847ba162ed44d78d3bb0c753d47d747ca63851d51ce3582420c44e567d97da73a91e8fc39c8010a36927c
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# This file was auto-generated by the schema_dev tool, based on the data in
|
2
|
+
# ./schema_dev.yml
|
3
|
+
# Please do not edit this file; any changes will be overwritten next time
|
4
|
+
# schema_dev gets run.
|
5
|
+
---
|
6
|
+
sudo: false
|
7
|
+
rvm:
|
8
|
+
- 2.1.5
|
9
|
+
gemfile:
|
10
|
+
- gemfiles/activerecord-4.2/Gemfile.mysql2
|
11
|
+
- gemfiles/activerecord-4.2/Gemfile.postgresql
|
12
|
+
- gemfiles/activerecord-4.2/Gemfile.sqlite3
|
13
|
+
env: POSTGRESQL_DB_USER=postgres MYSQL_DB_USER=travis
|
14
|
+
addons:
|
15
|
+
postgresql: '9.3'
|
16
|
+
before_script: bundle exec rake create_databases
|
17
|
+
after_script: bundle exec rake drop_databases
|
18
|
+
script: bundle exec rake travis
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 ronen barzel
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
[](http://badge.fury.io/rb/schema_plus_views)
|
2
|
+
[](http://travis-ci.org/SchemaPlus/schema_plus_views)
|
3
|
+
[](https://coveralls.io/r/SchemaPlus/schema_plus_views)
|
4
|
+
[](https://gemnasium.com/SchemaPlus/schema_plus_views)
|
5
|
+
|
6
|
+
# SchemaPlus::Views
|
7
|
+
|
8
|
+
SchemaPlus::Views adds support for creating and dropping views in ActiveRecord migrations, as well as querying views.
|
9
|
+
|
10
|
+
SchemaPlus::Views is part of the [SchemaPlus](https://github.com/SchemaPlus/) family of Ruby on Rails extension gems.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
<!-- SCHEMA_DEV: TEMPLATE INSTALLATION - begin -->
|
15
|
+
<!-- These lines are auto-inserted from a schema_dev template -->
|
16
|
+
As usual:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem "schema_plus_views" # in a Gemfile
|
20
|
+
gem.add_dependency "schema_plus_views" # in a .gemspec
|
21
|
+
```
|
22
|
+
|
23
|
+
To use with a rails app, also include
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem "schema_monkey_rails"
|
27
|
+
```
|
28
|
+
|
29
|
+
which creates a Railtie to that will insert SchemaPlus::Views appropriately into the rails stack. To use with Padrino, see [schema_monkey_padrino](https://github.com/SchemaPlus/schema_monkey_padrino).
|
30
|
+
|
31
|
+
<!-- SCHEMA_DEV: TEMPLATE INSTALLATION - end -->
|
32
|
+
|
33
|
+
## Compatibility
|
34
|
+
|
35
|
+
SchemaPlus::Views is tested on:
|
36
|
+
|
37
|
+
<!-- SCHEMA_DEV: MATRIX - begin -->
|
38
|
+
<!-- These lines are auto-generated by schema_dev based on schema_dev.yml -->
|
39
|
+
* ruby **2.1.5** with activerecord **4.2**, using **mysql2**, **sqlite3** or **postgresql**
|
40
|
+
|
41
|
+
<!-- SCHEMA_DEV: MATRIX - end -->
|
42
|
+
|
43
|
+
## Usage
|
44
|
+
|
45
|
+
### Creating views
|
46
|
+
|
47
|
+
In a migration, a view can be created using literal SQL:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
create_view :uncommented_posts, "SELECT * FROM posts LEFT OUTER JOIN comments ON comments.post_id = posts.id WHERE comments.id IS NULL"
|
51
|
+
```
|
52
|
+
|
53
|
+
or using an object that responds to `:to_sql`, such as a relation:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
create_view :posts_commented_by_staff, Post.joins(comment: user).where(users: {role: 'staff'}).uniq
|
57
|
+
```
|
58
|
+
|
59
|
+
(It's of course a questionable idea for your migrations to depend on your model definitions. But you *can* if you want.)
|
60
|
+
|
61
|
+
### Dropping views
|
62
|
+
|
63
|
+
In a migration:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
drop_view :posts_commented_by_staff
|
67
|
+
drop_view :uncommented_posts, :if_exists => true
|
68
|
+
```
|
69
|
+
|
70
|
+
### Using views
|
71
|
+
|
72
|
+
ActiveRecord models can be use views the same as ordinary tables. That is, for the above views you can define
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
class UncommentedPost < ActiveRecord::Base
|
76
|
+
end
|
77
|
+
|
78
|
+
class PostCommentedByStaff < ActiveRecord::Base
|
79
|
+
table_name = "posts_commented_by_staff"
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
### Querying views
|
84
|
+
|
85
|
+
You can look up the defined views analogously to looking up tables:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
connection.tables # => array of table names (defined by ActiveRecord)
|
89
|
+
connection.views # => array of names of views (defined by SchemaPlus::Views)
|
90
|
+
```
|
91
|
+
|
92
|
+
Notes:
|
93
|
+
|
94
|
+
1. For Mysql and SQLite3, ActiveRecord's `connection.tables` method would return views as well as tables; SchemaPlus::Views normalizes them to return only tables.
|
95
|
+
|
96
|
+
2. For PostgreSQL, `connection.views` does *not* return views prefixed with `pg_` as those are presumed to be internal.
|
97
|
+
|
98
|
+
### Querying view definitions
|
99
|
+
|
100
|
+
You can look up the definition of a view using
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
connection.view_definition(view_name) # => returns SQL string
|
104
|
+
```
|
105
|
+
|
106
|
+
This returns just the body of the definition, i.e. the part after the `CREATE VIEW 'name' AS` command.
|
107
|
+
|
108
|
+
|
109
|
+
## History
|
110
|
+
|
111
|
+
* 0.1.0 - Initial release, extracted from schema_plus 1.x
|
112
|
+
|
113
|
+
## Development & Testing
|
114
|
+
|
115
|
+
Are you interested in contributing to SchemaPlus::Views? Thanks! Please follow
|
116
|
+
the standard protocol: fork, feature branch, develop, push, and issue pull
|
117
|
+
request.
|
118
|
+
|
119
|
+
Some things to know about to help you develop and test:
|
120
|
+
|
121
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - begin -->
|
122
|
+
<!-- These lines are auto-inserted from a schema_dev template -->
|
123
|
+
* **schema_dev**: SchemaPlus::Views uses [schema_dev](https://github.com/SchemaPlus/schema_dev) to
|
124
|
+
facilitate running rspec tests on the matrix of ruby, activerecord, and database
|
125
|
+
versions that the gem supports, both locally and on
|
126
|
+
[travis-ci](http://travis-ci.org/SchemaPlus/schema_plus_views)
|
127
|
+
|
128
|
+
To to run rspec locally on the full matrix, do:
|
129
|
+
|
130
|
+
$ schema_dev bundle install
|
131
|
+
$ schema_dev rspec
|
132
|
+
|
133
|
+
You can also run on just one configuration at a time; For info, see `schema_dev --help` or the [schema_dev](https://github.com/SchemaPlus/schema_dev) README.
|
134
|
+
|
135
|
+
The matrix of configurations is specified in `schema_dev.yml` in
|
136
|
+
the project root.
|
137
|
+
|
138
|
+
|
139
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - end -->
|
140
|
+
|
141
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_PLUS_CORE - begin -->
|
142
|
+
<!-- These lines are auto-inserted from a schema_dev template -->
|
143
|
+
* **schema_plus_core**: SchemaPlus::Views uses the SchemaPlus::Core API that
|
144
|
+
provides middleware callback stacks to make it easy to extend
|
145
|
+
ActiveRecord's behavior. If that API is missing something you need for
|
146
|
+
your contribution, please head over to
|
147
|
+
[schema_plus_core](https://github/SchemaPlus/schema_plus_core) and open
|
148
|
+
an issue or pull request.
|
149
|
+
|
150
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_PLUS_CORE - end -->
|
151
|
+
|
152
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - begin -->
|
153
|
+
<!-- These lines are auto-inserted from a schema_dev template -->
|
154
|
+
* **schema_monkey**: SchemaPlus::Views is implemented as a
|
155
|
+
[schema_monkey](https://github.com/SchemaPlus/schema_monkey) client,
|
156
|
+
using [schema_monkey](https://github.com/SchemaPlus/schema_monkey)'s
|
157
|
+
convention-based protocols for extending ActiveRecord and using middleware stacks.
|
158
|
+
For more information see [schema_monkey](https://github.com/SchemaPlus/schema_monkey)'s README.
|
159
|
+
|
160
|
+
<!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - end -->
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module SchemaPlus::Views
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module AbstractAdapter
|
5
|
+
# Create a view given the SQL definition. Specify :force => true
|
6
|
+
# to first drop the view if it already exists.
|
7
|
+
def create_view(view_name, definition, options={})
|
8
|
+
definition = definition.to_sql if definition.respond_to? :to_sql
|
9
|
+
if options[:force]
|
10
|
+
drop_view(view_name, if_exists: true)
|
11
|
+
end
|
12
|
+
execute "CREATE VIEW #{quote_table_name(view_name)} AS #{definition}"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Drop the named view. Specify :if_exists => true
|
16
|
+
# to fail silently if the view doesn't exist.
|
17
|
+
def drop_view(view_name, options = {})
|
18
|
+
sql = "DROP VIEW"
|
19
|
+
sql += " IF EXISTS" if options[:if_exists]
|
20
|
+
sql += " #{quote_table_name(view_name)}"
|
21
|
+
execute sql
|
22
|
+
end
|
23
|
+
|
24
|
+
#####################################################################
|
25
|
+
#
|
26
|
+
# The functions below here are abstract; each subclass should
|
27
|
+
# define them all. Defining them here only for reference.
|
28
|
+
#
|
29
|
+
|
30
|
+
# (abstract) Returns the names of all views, as an array of strings
|
31
|
+
def views(name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; [] end
|
32
|
+
|
33
|
+
# (abstract) Returns the SQL definition of a given view. This is
|
34
|
+
# the literal SQL would come after 'CREATVE VIEW viewname AS ' in
|
35
|
+
# the SQL statement to create a view.
|
36
|
+
def view_definition(view_name, name = nil) raise "Internal Error: Connection adapter didn't override abstract function"; end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module SchemaPlus::Views
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module Mysql2Adapter
|
5
|
+
|
6
|
+
def views(name = nil)
|
7
|
+
views = []
|
8
|
+
select_all("SELECT table_name FROM information_schema.views WHERE table_schema = SCHEMA()", name).each do |row|
|
9
|
+
views << row["table_name"]
|
10
|
+
end
|
11
|
+
views
|
12
|
+
end
|
13
|
+
|
14
|
+
def view_definition(view_name, name = nil)
|
15
|
+
results = select_all("SELECT view_definition, check_option FROM information_schema.views WHERE table_schema = SCHEMA() AND table_name = #{quote(view_name)}", name)
|
16
|
+
return nil unless results.any?
|
17
|
+
row = results.first
|
18
|
+
sql = row["view_definition"]
|
19
|
+
sql.gsub!(%r{#{quote_table_name(current_database)}[.]}, '')
|
20
|
+
case row["check_option"]
|
21
|
+
when "CASCADED" then sql += " WITH CASCADED CHECK OPTION"
|
22
|
+
when "LOCAL" then sql += " WITH LOCAL CHECK OPTION"
|
23
|
+
end
|
24
|
+
sql
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SchemaPlus::Views
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module PostgresqlAdapter
|
5
|
+
|
6
|
+
def views(name = nil) #:nodoc:
|
7
|
+
sql = <<-SQL
|
8
|
+
SELECT viewname
|
9
|
+
FROM pg_views
|
10
|
+
WHERE schemaname = ANY (current_schemas(false))
|
11
|
+
AND viewname NOT LIKE 'pg\_%'
|
12
|
+
SQL
|
13
|
+
sql += " AND schemaname != 'postgis'" if adapter_name == 'PostGIS'
|
14
|
+
query(sql, name).map { |row| row[0] }
|
15
|
+
end
|
16
|
+
|
17
|
+
def view_definition(view_name, name = nil) #:nodoc:
|
18
|
+
result = query(<<-SQL, name)
|
19
|
+
SELECT pg_get_viewdef(oid)
|
20
|
+
FROM pg_class
|
21
|
+
WHERE relkind = 'v'
|
22
|
+
AND relname = '#{view_name}'
|
23
|
+
SQL
|
24
|
+
row = result.first
|
25
|
+
row.first.chomp(';') unless row.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module SchemaPlus::Views
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module Sqlite3Adapter
|
5
|
+
|
6
|
+
def views(name = nil)
|
7
|
+
execute("SELECT name FROM sqlite_master WHERE type='view'", name).collect{|row| row["name"]}
|
8
|
+
end
|
9
|
+
|
10
|
+
def view_definition(view_name, name = nil)
|
11
|
+
sql = execute("SELECT sql FROM sqlite_master WHERE type='view' AND name=#{quote(view_name)}", name).collect{|row| row["sql"]}.first
|
12
|
+
sql.sub(/^CREATE VIEW \S* AS\s+/im, '') unless sql.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module SchemaPlus::Views
|
2
|
+
module Middleware
|
3
|
+
|
4
|
+
module Dumper
|
5
|
+
module Tables
|
6
|
+
|
7
|
+
# Dump views
|
8
|
+
def after(env)
|
9
|
+
re_view_referent = %r{(?:(?i)FROM|JOIN) \S*\b(\S+)\b}
|
10
|
+
env.connection.views.each do |view_name|
|
11
|
+
next if env.dumper.ignored?(view_name)
|
12
|
+
view = View.new(name: view_name, definition: env.connection.view_definition(view_name))
|
13
|
+
env.dump.tables[view.name] = view
|
14
|
+
env.dump.depends(view.name, view.definition.scan(re_view_referent).flatten)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# quacks like a SchemaMonkey Dump::Table
|
19
|
+
class View < KeyStruct[:name, :definition]
|
20
|
+
def assemble(stream)
|
21
|
+
stream.puts(" create_view #{name.inspect}, #{definition.inspect}, :force => true\n")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Schema
|
28
|
+
module Tables
|
29
|
+
|
30
|
+
module Mysql
|
31
|
+
def after(env)
|
32
|
+
Tables.filter_out_views(env)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module Sqlite3
|
37
|
+
def after(env)
|
38
|
+
Tables.filter_out_views(env)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.filter_out_views(env)
|
43
|
+
env.tables -= env.connection.views(env.query_name)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'schema_plus/core'
|
2
|
+
|
3
|
+
module SchemaPlus
|
4
|
+
module Views
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require_relative 'views/version'
|
9
|
+
require_relative 'views/active_record/connection_adapters/abstract_adapter'
|
10
|
+
require_relative 'views/middleware'
|
11
|
+
|
12
|
+
module SchemaPlus::Views
|
13
|
+
module ActiveRecord
|
14
|
+
module ConnectionAdapters
|
15
|
+
autoload :Mysql2Adapter, 'schema_plus/views/active_record/connection_adapters/mysql2_adapter'
|
16
|
+
autoload :PostgresqlAdapter, 'schema_plus/views/active_record/connection_adapters/postgresql_adapter'
|
17
|
+
autoload :Sqlite3Adapter, 'schema_plus/views/active_record/connection_adapters/sqlite3_adapter'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
SchemaMonkey.register SchemaPlus::Views
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'schema_plus/views.rb'
|
data/schema_dev.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'schema_plus/views/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "schema_plus_views"
|
8
|
+
gem.version = SchemaPlus::Views::VERSION
|
9
|
+
gem.authors = ["ronen barzel"]
|
10
|
+
gem.email = ["ronen@barzel.org"]
|
11
|
+
gem.summary = %q{Adds support for views to ActiveRecord}
|
12
|
+
gem.homepage = "https://github.com/SchemaPlus/schema_plus_views"
|
13
|
+
gem.license = "MIT"
|
14
|
+
|
15
|
+
gem.files = `git ls-files -z`.split("\x0")
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "activerecord", "~> 4.2"
|
21
|
+
gem.add_dependency "schema_plus_core", "~> 0.1"
|
22
|
+
|
23
|
+
gem.add_development_dependency "bundler", "~> 1.7"
|
24
|
+
gem.add_development_dependency "rake", "~> 10.0"
|
25
|
+
gem.add_development_dependency "rspec", "~> 3.0"
|
26
|
+
gem.add_development_dependency "schema_dev", "~> 3.2"
|
27
|
+
gem.add_development_dependency "simplecov"
|
28
|
+
gem.add_development_dependency "simplecov-gem-profile"
|
29
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "with multiple schemas" do
|
4
|
+
def connection
|
5
|
+
ActiveRecord::Base.connection
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
newdb = case connection.adapter_name
|
10
|
+
when /^mysql/i then "CREATE SCHEMA IF NOT EXISTS schema_plus_views_test2"
|
11
|
+
when /^postgresql/i then "CREATE SCHEMA schema_plus_views_test2"
|
12
|
+
when /^sqlite/i then "ATTACH ':memory:' AS schema_plus_views_test2"
|
13
|
+
end
|
14
|
+
begin
|
15
|
+
ActiveRecord::Base.connection.execute newdb
|
16
|
+
rescue ActiveRecord::StatementInvalid => e
|
17
|
+
raise unless e.message =~ /already/
|
18
|
+
end
|
19
|
+
|
20
|
+
class User < ::ActiveRecord::Base ; end
|
21
|
+
end
|
22
|
+
|
23
|
+
before(:each) do
|
24
|
+
ActiveRecord::Schema.define do
|
25
|
+
create_table :users, :force => true do |t|
|
26
|
+
t.string :login
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
connection.execute 'DROP TABLE IF EXISTS schema_plus_views_test2.users'
|
31
|
+
connection.execute 'CREATE TABLE schema_plus_views_test2.users (id ' + case connection.adapter_name
|
32
|
+
when /^mysql/i then "integer primary key auto_increment"
|
33
|
+
when /^postgresql/i then "serial primary key"
|
34
|
+
when /^sqlite/i then "integer primary key autoincrement"
|
35
|
+
end + ", login varchar(255))"
|
36
|
+
end
|
37
|
+
|
38
|
+
context "with views in each schema" do
|
39
|
+
around(:each) do |example|
|
40
|
+
begin
|
41
|
+
example.run
|
42
|
+
ensure
|
43
|
+
connection.execute 'DROP VIEW schema_plus_views_test2.myview' rescue nil
|
44
|
+
connection.execute 'DROP VIEW myview' rescue nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
before(:each) do
|
49
|
+
connection.views.each { |view| connection.drop_view view }
|
50
|
+
connection.execute 'CREATE VIEW schema_plus_views_test2.myview AS SELECT * FROM users'
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should not find views in other schema" do
|
54
|
+
expect(connection.views).to be_empty
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should find views in this schema" do
|
58
|
+
connection.execute 'CREATE VIEW myview AS SELECT * FROM users'
|
59
|
+
expect(connection.views).to eq(['myview'])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when using PostGIS", :postgresql => :only do
|
64
|
+
before(:all) do
|
65
|
+
begin
|
66
|
+
connection.execute "CREATE SCHEMA postgis"
|
67
|
+
rescue ActiveRecord::StatementInvalid => e
|
68
|
+
raise unless e.message =~ /already exists/
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
around(:each) do |example|
|
73
|
+
begin
|
74
|
+
connection.execute "SET search_path to '$user','public','postgis'"
|
75
|
+
example.run
|
76
|
+
ensure
|
77
|
+
connection.execute "SET search_path to '$user','public'"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
before(:each) do
|
82
|
+
allow(connection).to receive(:adapter_name).and_return('PostGIS')
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should hide views in postgis schema" do
|
86
|
+
begin
|
87
|
+
connection.create_view "postgis.hidden", "select 1", :force => true
|
88
|
+
connection.create_view :myview, "select 2", :force => true
|
89
|
+
expect(connection.views).to eq(["myview"])
|
90
|
+
ensure
|
91
|
+
connection.execute 'DROP VIEW postgis.hidden' rescue nil
|
92
|
+
connection.execute 'DROP VIEW myview' rescue nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
data/spec/sanity_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
# A basic sanity check to have as a spec when first starting. Feel free to delete this
|
5
|
+
# once you've got real content.
|
6
|
+
|
7
|
+
describe "Sanity Check" do
|
8
|
+
|
9
|
+
it "database is connected" do
|
10
|
+
expect(ActiveRecord::Base).to be_connected
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'simplecov-gem-profile'
|
3
|
+
SimpleCov.start "gem"
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
|
+
|
8
|
+
require 'rspec'
|
9
|
+
require 'active_record'
|
10
|
+
require 'schema_plus_views'
|
11
|
+
require 'schema_dev/rspec'
|
12
|
+
|
13
|
+
SchemaDev::Rspec.setup
|
14
|
+
|
15
|
+
Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.warnings = true
|
19
|
+
config.around(:each) do |example|
|
20
|
+
ActiveRecord::Migration.suppress_messages do
|
21
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
22
|
+
ActiveRecord::Migration.drop_table table, force: :cascade
|
23
|
+
end
|
24
|
+
example.run
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
SimpleCov.command_name "[ruby #{RUBY_VERSION} - ActiveRecord #{::ActiveRecord::VERSION::STRING} - #{ActiveRecord::Base.connection.adapter_name}]"
|
data/spec/views_spec.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Item < ActiveRecord::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class AOnes < ActiveRecord::Base
|
7
|
+
end
|
8
|
+
|
9
|
+
class ABOnes < ActiveRecord::Base
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ActiveRecord do
|
13
|
+
|
14
|
+
let(:schema) { ActiveRecord::Schema }
|
15
|
+
|
16
|
+
let(:migration) { ActiveRecord::Migration }
|
17
|
+
|
18
|
+
let(:connection) { ActiveRecord::Base.connection }
|
19
|
+
|
20
|
+
context "views" do
|
21
|
+
|
22
|
+
around(:each) do |example|
|
23
|
+
define_schema_and_data
|
24
|
+
example.run
|
25
|
+
drop_definitions
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should query correctly" do
|
29
|
+
expect(AOnes.all.collect(&:s)).to eq(%W[one_one one_two])
|
30
|
+
expect(ABOnes.all.collect(&:s)).to eq(%W[one_one])
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should instrospect" do
|
34
|
+
# for postgresql, ignore views named pg_*
|
35
|
+
expect(connection.views.sort).to eq(%W[a_ones ab_ones])
|
36
|
+
expect(connection.view_definition('a_ones')).to match(%r{^ ?SELECT .*b.*,.*s.* FROM .*items.* WHERE .*a.* = 1}mi)
|
37
|
+
expect(connection.view_definition('ab_ones')).to match(%r{^ ?SELECT .*s.* FROM .*a_ones.* WHERE .*b.* = 1}mi)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should not be listed as a table" do
|
41
|
+
expect(connection.tables).not_to include('a_ones')
|
42
|
+
expect(connection.tables).not_to include('ab_ones')
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
it "should be included in schema dump" do
|
47
|
+
expect(dump).to match(%r{create_view "a_ones", " ?SELECT .*b.*,.*s.* FROM .*items.* WHERE .*a.* = 1.*, :force => true}mi)
|
48
|
+
expect(dump).to match(%r{create_view "ab_ones", " ?SELECT .*s.* FROM .*a_ones.* WHERE .*b.* = 1.*, :force => true}mi)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should be included in schema dump in dependency order" do
|
52
|
+
expect(dump).to match(%r{create_table "items".*create_view "a_ones".*create_view "ab_ones"}m)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should not be included in schema if listed in ignore_tables" do
|
56
|
+
dump(ignore_tables: /b_/) do |dump|
|
57
|
+
expect(dump).to match(%r{create_view "a_ones", " ?SELECT .*b.*,.*s.* FROM .*items.* WHERE .*a.* = 1.*, :force => true}mi)
|
58
|
+
expect(dump).not_to match(%r{"ab_ones"})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
it "dump should not reference current database" do
|
64
|
+
# why check this? mysql default to providing the view definition
|
65
|
+
# with tables explicitly scoped to the current database, which
|
66
|
+
# resulted in the dump being bound to the current database. this
|
67
|
+
# caused trouble for rails, in which creates the schema dump file
|
68
|
+
# when in the (say) development database, but then uses it to
|
69
|
+
# initialize the test database when testing. this meant that the
|
70
|
+
# test database had views into the development database.
|
71
|
+
db = connection.respond_to?(:current_database)? connection.current_database : SchemaDev::Rspec.db_configuration[:database]
|
72
|
+
expect(dump).not_to match(%r{#{connection.quote_table_name(db)}[.]})
|
73
|
+
end
|
74
|
+
|
75
|
+
context "duplicate view creation" do
|
76
|
+
around(:each) do |example|
|
77
|
+
migration.suppress_messages do
|
78
|
+
begin
|
79
|
+
migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=1)')
|
80
|
+
example.run
|
81
|
+
ensure
|
82
|
+
migration.drop_view('dupe_me')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
it "should raise an error by default" do
|
89
|
+
expect {migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=2)')}.to raise_error ActiveRecord::StatementInvalid
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should override existing definition if :force true" do
|
93
|
+
migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=2)', :force => true)
|
94
|
+
expect(connection.view_definition('dupe_me')).to match(%r{WHERE .*a.*=.*2}i)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "dropping views" do
|
99
|
+
it "should raise an error if the view doesn't exist" do
|
100
|
+
expect { migration.drop_view('doesnt_exist') }.to raise_error ActiveRecord::StatementInvalid
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should fail silently when using if_exists option" do
|
104
|
+
expect { migration.drop_view('doesnt_exist', :if_exists => true) }.not_to raise_error
|
105
|
+
end
|
106
|
+
|
107
|
+
context "with a view that exists" do
|
108
|
+
before { migration.create_view('view_that_exists', 'SELECT * FROM items WHERE (a=1)') }
|
109
|
+
|
110
|
+
it "should succeed" do
|
111
|
+
migration.drop_view('view_that_exists')
|
112
|
+
expect(connection.views).not_to include('view_that_exists')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "in mysql", :mysql => :only do
|
118
|
+
|
119
|
+
around(:each) do |example|
|
120
|
+
migration.suppress_messages do
|
121
|
+
begin
|
122
|
+
migration.drop_view :check if connection.views.include? 'check'
|
123
|
+
example.run
|
124
|
+
ensure
|
125
|
+
migration.drop_view :check if connection.views.include? 'check'
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should introspect WITH CHECK OPTION" do
|
131
|
+
migration.create_view :check, 'SELECT * FROM items WHERE (a=2) WITH CHECK OPTION'
|
132
|
+
expect(connection.view_definition('check')).to match(%r{WITH CASCADED CHECK OPTION$})
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should introspect WITH CASCADED CHECK OPTION" do
|
136
|
+
migration.create_view :check, 'SELECT * FROM items WHERE (a=2) WITH CASCADED CHECK OPTION'
|
137
|
+
expect(connection.view_definition('check')).to match(%r{WITH CASCADED CHECK OPTION$})
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should introspect WITH LOCAL CHECK OPTION" do
|
141
|
+
migration.create_view :check, 'SELECT * FROM items WHERE (a=2) WITH LOCAL CHECK OPTION'
|
142
|
+
expect(connection.view_definition('check')).to match(%r{WITH LOCAL CHECK OPTION$})
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
protected
|
148
|
+
|
149
|
+
def define_schema_and_data
|
150
|
+
migration.suppress_messages do
|
151
|
+
connection.views.each do |view| connection.drop_view view end
|
152
|
+
connection.tables.each do |table| connection.drop_table table, cascade: true end
|
153
|
+
|
154
|
+
schema.define do
|
155
|
+
|
156
|
+
create_table :items, :force => true do |t|
|
157
|
+
t.integer :a
|
158
|
+
t.integer :b
|
159
|
+
t.string :s
|
160
|
+
end
|
161
|
+
|
162
|
+
create_view :a_ones, Item.select('b, s').where(:a => 1)
|
163
|
+
create_view :ab_ones, "select s from a_ones where b = 1"
|
164
|
+
create_view :pg_dummy_internal, "select 1" if SchemaDev::Rspec::Helpers.postgresql?
|
165
|
+
end
|
166
|
+
end
|
167
|
+
connection.execute "insert into items (a, b, s) values (1, 1, 'one_one')"
|
168
|
+
connection.execute "insert into items (a, b, s) values (1, 2, 'one_two')"
|
169
|
+
connection.execute "insert into items (a, b, s) values (2, 1, 'two_one')"
|
170
|
+
connection.execute "insert into items (a, b, s) values (2, 2, 'two_two')"
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
def drop_definitions
|
175
|
+
migration.suppress_messages do
|
176
|
+
schema.define do
|
177
|
+
drop_view "ab_ones"
|
178
|
+
drop_view "a_ones"
|
179
|
+
drop_table "items"
|
180
|
+
drop_view :pg_dummy_internal if SchemaDev::Rspec::Helpers.postgresql?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def dump(opts={})
|
186
|
+
StringIO.open { |stream|
|
187
|
+
ActiveRecord::SchemaDumper.ignore_tables = Array.wrap(opts[:ignore_tables])
|
188
|
+
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
|
189
|
+
yield stream.string if block_given?
|
190
|
+
stream.string
|
191
|
+
}
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
metadata
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: schema_plus_views
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- ronen barzel
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: schema_plus_core
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.7'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: schema_dev
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov-gem-profile
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- ronen@barzel.org
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".travis.yml"
|
134
|
+
- Gemfile
|
135
|
+
- LICENSE.txt
|
136
|
+
- README.md
|
137
|
+
- Rakefile
|
138
|
+
- gemfiles/Gemfile.base
|
139
|
+
- gemfiles/activerecord-4.2/Gemfile.base
|
140
|
+
- gemfiles/activerecord-4.2/Gemfile.mysql2
|
141
|
+
- gemfiles/activerecord-4.2/Gemfile.postgresql
|
142
|
+
- gemfiles/activerecord-4.2/Gemfile.sqlite3
|
143
|
+
- lib/schema_plus/views.rb
|
144
|
+
- lib/schema_plus/views/active_record/connection_adapters/abstract_adapter.rb
|
145
|
+
- lib/schema_plus/views/active_record/connection_adapters/mysql2_adapter.rb
|
146
|
+
- lib/schema_plus/views/active_record/connection_adapters/postgresql_adapter.rb
|
147
|
+
- lib/schema_plus/views/active_record/connection_adapters/sqlite3_adapter.rb
|
148
|
+
- lib/schema_plus/views/middleware.rb
|
149
|
+
- lib/schema_plus/views/version.rb
|
150
|
+
- lib/schema_plus_views.rb
|
151
|
+
- schema_dev.yml
|
152
|
+
- schema_plus_views.gemspec
|
153
|
+
- spec/named_schemas_spec.rb
|
154
|
+
- spec/sanity_spec.rb
|
155
|
+
- spec/spec_helper.rb
|
156
|
+
- spec/views_spec.rb
|
157
|
+
homepage: https://github.com/SchemaPlus/schema_plus_views
|
158
|
+
licenses:
|
159
|
+
- MIT
|
160
|
+
metadata: {}
|
161
|
+
post_install_message:
|
162
|
+
rdoc_options: []
|
163
|
+
require_paths:
|
164
|
+
- lib
|
165
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
requirements: []
|
176
|
+
rubyforge_project:
|
177
|
+
rubygems_version: 2.2.2
|
178
|
+
signing_key:
|
179
|
+
specification_version: 4
|
180
|
+
summary: Adds support for views to ActiveRecord
|
181
|
+
test_files:
|
182
|
+
- spec/named_schemas_spec.rb
|
183
|
+
- spec/sanity_spec.rb
|
184
|
+
- spec/spec_helper.rb
|
185
|
+
- spec/views_spec.rb
|