schema_monkey 1.0.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +0 -1
- data/Gemfile +2 -0
- data/README.md +204 -28
- data/lib/schema_monkey.rb +30 -17
- data/lib/schema_monkey/active_record.rb +25 -0
- data/lib/schema_monkey/client.rb +65 -0
- data/lib/schema_monkey/errors.rb +6 -0
- data/lib/schema_monkey/{tool/module.rb → module.rb} +10 -7
- data/lib/schema_monkey/monkey.rb +31 -0
- data/lib/schema_monkey/{tool/rake.rb → rake.rb} +1 -1
- data/lib/schema_monkey/stack.rb +44 -0
- data/lib/schema_monkey/{tool/tasks → tasks}/insert.rake +0 -0
- data/lib/schema_monkey/version.rb +1 -1
- data/schema_dev.yml +0 -1
- data/schema_monkey.gemspec +2 -2
- data/spec/active_record_spec.rb +75 -0
- data/spec/middleware_spec.rb +0 -7
- data/spec/spec_helper.rb +2 -2
- metadata +18 -41
- data/lib/schema_monkey/core_extensions.rb +0 -23
- data/lib/schema_monkey/core_extensions/active_record/base.rb +0 -31
- data/lib/schema_monkey/core_extensions/active_record/connection_adapters/abstract_adapter.rb +0 -38
- data/lib/schema_monkey/core_extensions/active_record/connection_adapters/mysql2_adapter.rb +0 -31
- data/lib/schema_monkey/core_extensions/active_record/connection_adapters/postgresql_adapter.rb +0 -30
- data/lib/schema_monkey/core_extensions/active_record/connection_adapters/schema_statements.rb +0 -83
- data/lib/schema_monkey/core_extensions/active_record/connection_adapters/sqlite3_adapter.rb +0 -33
- data/lib/schema_monkey/core_extensions/active_record/connection_adapters/table_definition.rb +0 -42
- data/lib/schema_monkey/core_extensions/active_record/migration/command_recorder.rb +0 -19
- data/lib/schema_monkey/core_extensions/active_record/schema_dumper.rb +0 -227
- data/lib/schema_monkey/core_extensions/middleware.rb +0 -62
- data/lib/schema_monkey/tool.rb +0 -43
- data/lib/schema_monkey/tool/client.rb +0 -67
- data/lib/schema_monkey/tool/errors.rb +0 -4
- data/lib/schema_monkey/tool/monkey.rb +0 -46
- data/lib/schema_monkey/tool/stack.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2090c17d3f5bba79e1885f2f76a22a8c0bfcb389
|
4
|
+
data.tar.gz: d8fecf5bea771ace12cf1511583098408f9e2f38
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2fdef632c27ed6619821a0b9fed86d1931a86eea897991ca0a98c88af7f7c3dfcb855243499f29af6c9d4f25397e6c3e42d2a630555eea14b820709c48cb808
|
7
|
+
data.tar.gz: ee53c8e8d0b1d7cb4dd824096cf208475ab16dc56cd2a9c5f2e84a844d00adcff40a60345809a30c98ed1e39bbd076c48417e642c01a1126836d1b060ebc5749
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -5,37 +5,227 @@
|
|
5
5
|
|
6
6
|
# SchemaMonkey
|
7
7
|
|
8
|
-
SchemaMonkey is a behind-the-scenes gem to
|
8
|
+
SchemaMonkey is a behind-the-scenes gem to make it easy to write extensions to ActiveRecord. It provides:
|
9
9
|
|
10
|
-
* A
|
10
|
+
* A simple convention-based mechanism to insert modules into ActiveRecord modules.
|
11
|
+
* A simple convention-based mechanism to create and use [Modware](https://rubygems.org/gems/modware) middleware stacks.
|
11
12
|
|
12
|
-
|
13
|
+
SchemaMonkey by itself doesn't add any behavior -- SchemaMonkey is intended to make it easy to add clients that define methods and stacks, that are then available to other clients or the app. (In particular, most clients of SchemaMonkey will depend on [schema_plus_core](https://github.com/SchemaPlus/schema_plus_core), which is a SchemaMonkey client that provides an "internal extension API" to ActiveRecord.)
|
13
14
|
|
15
|
+
## Installation
|
14
16
|
|
15
|
-
|
17
|
+
As usual:
|
16
18
|
|
19
|
+
```ruby
|
20
|
+
gem "schema_monkey" # in a Gemfile
|
21
|
+
gem.add_dependency "schema_monkey" # in a .gemspec
|
22
|
+
```
|
17
23
|
|
18
|
-
|
24
|
+
To use with a rails app, also include
|
19
25
|
|
20
|
-
|
26
|
+
```ruby
|
27
|
+
gem "schema_monkey_rails"
|
28
|
+
```
|
29
|
+
|
30
|
+
which creates a Railtie to insert SchemaMonkey appropriately into the rails stack. To use with Padrino, see [schema_monkey_padrino](https://github.com/SchemaPlus/schema_monkey_padrino).
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
SchemaMonkey works with the notion of a "client" -- which is a module containining definitions. A typical SchemaMonkey client looks like
|
21
35
|
|
22
36
|
```ruby
|
23
|
-
|
24
|
-
|
37
|
+
require 'schema_monkey'
|
38
|
+
require 'other-client1' # if needed
|
39
|
+
require 'other-client2' # as needed
|
40
|
+
|
41
|
+
module MyClient
|
42
|
+
|
43
|
+
module ActiveRecord
|
44
|
+
#
|
45
|
+
# active record extensions, if any
|
46
|
+
#
|
47
|
+
end
|
48
|
+
|
49
|
+
module Middleware
|
50
|
+
#
|
51
|
+
# middleware stack modules, if any
|
52
|
+
#
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
25
56
|
|
26
|
-
#
|
27
|
-
gem "schema_monkey", "~> <MAJOR>.<MINOR>", ">= <MAJOR>.<MINOR>.<PATCH>"
|
57
|
+
SchemaMonkey.register MyClient # <--- That's it! No configuration needed
|
28
58
|
```
|
29
59
|
|
30
|
-
|
60
|
+
of course a typical client will be split into files corresponding to submodules; e.g. here's the top level of [schema_plus_indexes](https://github.com/SchemaPlus/schema_plus_indexes):
|
31
61
|
|
32
|
-
|
62
|
+
```ruby
|
63
|
+
require 'schema_plus/core'
|
64
|
+
|
65
|
+
require_relative 'schema_plus_indexes/active_record/base'
|
66
|
+
require_relative 'schema_plus_indexes/active_record/connection_adapters/abstract_adapter'
|
67
|
+
require_relative 'schema_plus_indexes/active_record/connection_adapters/index_definition'
|
68
|
+
|
69
|
+
require_relative 'schema_plus_indexes/middleware/dumper'
|
70
|
+
require_relative 'schema_plus_indexes/middleware/migration'
|
71
|
+
require_relative 'schema_plus_indexes/middleware/model'
|
72
|
+
require_relative 'schema_plus_indexes/middleware/query'
|
73
|
+
|
74
|
+
SchemaMonkey.register SchemaPlusIndexes
|
75
|
+
```
|
76
|
+
|
77
|
+
The details of ActiveRecord exentions and Middleware modules are described below.
|
78
|
+
|
79
|
+
## ActiveRecord Extensions
|
80
|
+
|
81
|
+
Here's a simple example of an extension to ActiveRecord:
|
33
82
|
|
34
83
|
```ruby
|
35
|
-
|
84
|
+
require 'schema_monkey'
|
85
|
+
|
86
|
+
module PracticalJoker
|
87
|
+
module ActiveRecord
|
88
|
+
module Base
|
89
|
+
|
90
|
+
def save(*args)
|
91
|
+
raise "April Fools!" if Time.now.yday == 31
|
92
|
+
super
|
93
|
+
end
|
94
|
+
|
95
|
+
module ClassMethods
|
96
|
+
def columns
|
97
|
+
raise "Boo!" if Time.now.yday == 304
|
98
|
+
super
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
SchemaMonkey.register PracticalJoker
|
108
|
+
```
|
109
|
+
|
110
|
+
SchemaMonkey inserts each submodule of `MyClient::ActiveRecord` into the corresponding module of ActiveRecord, with `ClassMethods` inserted as class methods.
|
111
|
+
|
112
|
+
This works for arbitrary submodule paths, such as `MyClient::ActiveRecord::ConnectionAdapters::TableDefinition`. SchemaMonkey will raise an error if the client defines a module that does not have a corresponding ActiveRecord module.
|
113
|
+
|
114
|
+
Notice that insertion is done using `:prepend`, so that client modules can override existing methods and use `super`.
|
115
|
+
|
116
|
+
### DBMS-specific insertion
|
117
|
+
|
118
|
+
If a client module's name includes one the dbms names `Mysql`, `PostgreSQL` or `SQLite3` (case insensitive), the insertion will only be performed if that's the dbms in use. So, e.g. `MyClient::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter` will only be inserted if the app is using PostgreSQL.
|
119
|
+
|
120
|
+
Additionally, for ActiveRecord modules that are not inherently dbms-specific, you can use one of the dbms names (case insensitive) as a component in the client module's path to do dbms-specific insertion. E.g.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
module MyClient
|
124
|
+
module ActiveRecord
|
125
|
+
module ConnectionAdapters
|
126
|
+
module Sqlite3
|
127
|
+
module TableDefinition
|
128
|
+
#
|
129
|
+
# SQLite3-specific enhancements to
|
130
|
+
# ActiveRecord::ConnectionAdapters::TableDefinition
|
131
|
+
#
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
The dbms name component can be anywhere in the module path after `MyClient::ActiveRecord`
|
140
|
+
|
141
|
+
### `insert` vs `prepend`
|
142
|
+
|
143
|
+
|
144
|
+
* By default, SchemaMonkey inserts a client module using `prepend`, and a client ClassMethods module using `singleton_class.prepend`. This allows overriding existing methods and using `super`. On insertion, Ruby will of course call the module's `self.prepended` method, if one is defined.
|
145
|
+
|
146
|
+
* However, if the client module defines a module method `self.included` then SchemaMonkey will use `include` for a module and `singleton_class.include` for a ClassMethods module -- and Ruby will of course call that method.
|
147
|
+
|
148
|
+
Note that in the case of a ClassMethods module, when Ruby calls `self.prepended` or `self.included`, it will pass the singleton class. For convience SchemaMonkey will also call `self.extended` if defined passing it the ActiveRecord module itself, just as Ruby would if `extend` were used.
|
149
|
+
|
150
|
+
## Middleware Modlues
|
151
|
+
|
152
|
+
SchemaMonkey provides a convention-based front end to using [Modware](https://github.com/ronen/modware) middleware stacks.
|
153
|
+
|
154
|
+
SchemaMonkey uses Ruby modules to organize the stacks: Each stack is contained in a submodule of `SchemaMonkey::Middleware`
|
155
|
+
|
156
|
+
### Defining a stack
|
157
|
+
|
158
|
+
Here's an example of defining a middleware stack:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
module MyClient
|
162
|
+
module Middleware
|
163
|
+
module Index
|
164
|
+
module Exists
|
165
|
+
Env = [:connection, :table_name, :column_name, :options, :result]
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
```
|
171
|
+
|
172
|
+
This defines a stack available at `SchemaMonkey::Middleware::Index::Exists`. You can use any module path you want for organizational convenience. The const `Env` signals to SchemaMonkey to create a stack at that location; the environment object for the stack will have the listed fields. (Env actually can be an array of symbols or a Class, as per `Modware::Stack.new`.)
|
173
|
+
|
174
|
+
SchemaMonkey will raise an error if a stack had already been defined there.
|
175
|
+
|
176
|
+
The defined module has a module method `start` that delegates to `Modware::Stack.start`. Here's an example of using the above stack as a wrapper around ActiveRecord's `index_exists?` method:
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
module MyClient
|
180
|
+
module ActiveRecord
|
181
|
+
module ConnectionAdapters
|
182
|
+
module SchemaStatements
|
183
|
+
def index_exists?(table_name, column_name, options = {})
|
184
|
+
SchemaMonkey::Middleware::Index::Exists.start(connection: self, table_name: table_name, column_name: column_name, options: options) { |env|
|
185
|
+
env.result = super env.table_name, env.column_name, env.options
|
186
|
+
}.result
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
36
192
|
```
|
37
193
|
|
38
|
-
|
194
|
+
This is a fairly typical idiom for wrapping behavior in a stack:
|
195
|
+
|
196
|
+
1. Pass `self` and the method arguments to the stack environment
|
197
|
+
2. Call the base implementation, passing it argument values from the environment (giving clients a chance to modify them in `before` or `around` methods)
|
198
|
+
3. Place the result in the environment (giving clients a chance to modify it in `after` or `around` methods
|
199
|
+
4. `start` returns the environment object -- the method returns the result that's stored in the environment
|
200
|
+
|
201
|
+
### Inserting Middleware in a stack
|
202
|
+
|
203
|
+
If an earlier client defined a stack, a later client can insert middleware into the stack:
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
require 'my_client' # earlier client defines the stack
|
207
|
+
|
208
|
+
module UColumnImpliesUnique
|
209
|
+
module Middlware
|
210
|
+
module Index
|
211
|
+
module Exists
|
212
|
+
def before(env)
|
213
|
+
env.options.reverse_merge!(unique: env.column_name.start_with? 'u')
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
SchemaMonkey.register(UColumnImpliesUnique)
|
221
|
+
```
|
222
|
+
|
223
|
+
SchemaMonkey uses the module `MyLaterClient::Middleware::Index::Exists` as [Modware](https://github.com/ronen/modware) middleware for the corresponding stack. The middleware module can define middleware methods `before`, `arround`, `after`, or `implementation` as per [Modware](https://github.com/ronen/modware)
|
224
|
+
|
225
|
+
Note that the distinguishing feature between defining and using a stack is whether `Env` is defined.
|
226
|
+
|
227
|
+
|
228
|
+
|
39
229
|
|
40
230
|
## Compatibility
|
41
231
|
|
@@ -43,16 +233,10 @@ SchemaMonkey is tested on:
|
|
43
233
|
|
44
234
|
<!-- SCHEMA_DEV: MATRIX - begin -->
|
45
235
|
<!-- These lines are auto-generated by schema_dev based on schema_dev.yml -->
|
46
|
-
* ruby **1.9.3** with activerecord **4.2**, using **mysql2**, **sqlite3** or **postgresql**
|
47
236
|
* ruby **2.1.5** with activerecord **4.2**, using **mysql2**, **sqlite3** or **postgresql**
|
48
237
|
|
49
238
|
<!-- SCHEMA_DEV: MATRIX - end -->
|
50
239
|
|
51
|
-
## Usage
|
52
|
-
|
53
|
-
|
54
|
-
**Sorry -- no real documentation yet. See examples in [schema_plus_indexes](https://github/SchemaPlus/schema_plus_indexes) and [schema_plus_pg_indexes](https://github/SchemaPlus/schema_plus_pg_indexes)**
|
55
|
-
|
56
240
|
|
57
241
|
|
58
242
|
## Development & Testing
|
@@ -62,14 +246,6 @@ the standard protocol: fork, feature branch, develop, push, and issue pull reque
|
|
62
246
|
|
63
247
|
Some things to know about to help you develop and test:
|
64
248
|
|
65
|
-
* SchemaMonkey is a wrapper around two subparts:
|
66
|
-
|
67
|
-
* `SchemaMonkey::Tool` provides the convention-based mechanism for registering clients that extend ActiveRecord using `include`'s and middleware.
|
68
|
-
|
69
|
-
* `SchemaMonkey::CoreExtensions` defines the ActiveRecord extension API. It is itself just the first client registered with `SchemaMonkey::Tool`. **Ugh. Currently no specs for `SchemaMonkey::CoreExtensions`; testing indirectly by testing the client gems that use it. Working on it...**
|
70
|
-
|
71
|
-
One day might actually split these into separate gems to decouple their development and testing. And actually the middleware mechanism of `SchemaMonkey::Tool` could be a split out separate gem.
|
72
|
-
|
73
249
|
* **schema_dev**: SchemaMonkey uses [schema_dev](https://github.com/SchemaPlus/schema_dev) to
|
74
250
|
facilitate running rspec tests on the matrix of ruby, rails, and database
|
75
251
|
versions that the gem supports, both locally and on
|
data/lib/schema_monkey.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_support/core_ext/string'
|
3
|
+
require 'its-it'
|
4
|
+
require 'modware'
|
5
|
+
|
6
|
+
require_relative "schema_monkey/active_record"
|
7
|
+
require_relative "schema_monkey/client"
|
8
|
+
require_relative "schema_monkey/errors"
|
9
|
+
require_relative "schema_monkey/module"
|
10
|
+
require_relative "schema_monkey/monkey"
|
11
|
+
require_relative "schema_monkey/stack"
|
12
|
+
require_relative 'schema_monkey/rake'
|
3
13
|
|
4
14
|
#
|
5
15
|
# Middleware contents will be created dynamically
|
@@ -10,31 +20,34 @@ module SchemaMonkey
|
|
10
20
|
end
|
11
21
|
|
12
22
|
#
|
13
|
-
#
|
23
|
+
#
|
14
24
|
#
|
15
25
|
module SchemaMonkey
|
26
|
+
|
27
|
+
DBMS = [:PostgreSQL, :Mysql, :SQLite3]
|
28
|
+
|
16
29
|
def self.register(mod)
|
17
|
-
|
30
|
+
monkey.register(mod)
|
18
31
|
end
|
19
32
|
|
20
33
|
def self.insert(opts={})
|
21
|
-
|
34
|
+
monkey.insert(opts)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def self.monkey
|
40
|
+
@monkey ||= Monkey.new
|
22
41
|
end
|
23
42
|
|
24
|
-
def self.
|
25
|
-
|
43
|
+
def self.reset_for_rspec
|
44
|
+
@monkey = nil
|
45
|
+
self.reset_middleware
|
26
46
|
end
|
27
47
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
48
|
+
def self.reset_middleware
|
49
|
+
SchemaMonkey.send :remove_const, :Middleware
|
50
|
+
SchemaMonkey.send :const_set, :Middleware, ::Module.new
|
32
51
|
end
|
33
52
|
|
34
|
-
MiddlewareError = Tool::MiddlewareError
|
35
53
|
end
|
36
|
-
|
37
|
-
#
|
38
|
-
# Register CoreExtensions
|
39
|
-
#
|
40
|
-
SchemaMonkey::Tool.register(SchemaMonkey::CoreExtensions)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SchemaMonkey
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
module AbstractAdapter
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
dbm = case adapter_name
|
8
|
+
when /^MySQL/i then :Mysql
|
9
|
+
when 'PostgreSQL', 'PostGIS' then :PostgreSQL
|
10
|
+
when 'SQLite' then :SQLite3
|
11
|
+
end
|
12
|
+
SchemaMonkey.insert(dbm: dbm)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.insert(relative_path, mod)
|
18
|
+
class_methods = relative_path.sub!(/::ClassMethods$/, '')
|
19
|
+
base = Module.const_lookup(::ActiveRecord, relative_path)
|
20
|
+
raise InsertionError, "No module ActiveRecord::#{relative_path} to insert #{mod}" unless base
|
21
|
+
Module.insert (class_methods ? base.singleton_class : base), mod
|
22
|
+
mod.extended base if class_methods and mod.respond_to? :extended
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module SchemaMonkey
|
2
|
+
class Client
|
3
|
+
|
4
|
+
def initialize(mod)
|
5
|
+
@root = mod
|
6
|
+
@inserted_middleware = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def insert(dbm: nil)
|
10
|
+
insert_active_record(dbm: dbm)
|
11
|
+
insert_middleware(dbm: dbm)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def insert_active_record(dbm: nil)
|
17
|
+
# Kernel.warn "--- inserting active_record for #{@root}, dbm=#{dbm.inspect}"
|
18
|
+
find_modules(:ActiveRecord, dbm: dbm).each do |mod|
|
19
|
+
next if mod.is_a? Class
|
20
|
+
relative_path = canonicalize_path(mod, :ActiveRecord, dbm)
|
21
|
+
ActiveRecord.insert(relative_path, mod)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def insert_middleware(dbm: nil)
|
26
|
+
find_modules(:Middleware, dbm: dbm).each do |mod|
|
27
|
+
next if @inserted_middleware[mod]
|
28
|
+
relative_path = canonicalize_path(mod, :Middleware, dbm)
|
29
|
+
Stack.insert(relative_path, mod) unless relative_path.empty?
|
30
|
+
@inserted_middleware[mod] = true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def canonicalize_path(mod, base, dbm)
|
35
|
+
path = mod.to_s.sub(/^#{@root}::#{base}::/, '')
|
36
|
+
if dbm
|
37
|
+
path = path.split('::')
|
38
|
+
if (i = path.find_index(&it =~ /\b#{dbm}\b/i)) # delete first occurence
|
39
|
+
path.delete_at i
|
40
|
+
end
|
41
|
+
path = path.join('::').gsub(/#{dbm}/i, dbm.to_s) # canonicalize case for things like PostgreSQLAdapter
|
42
|
+
end
|
43
|
+
path
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_modules(container, dbm: nil)
|
47
|
+
return [] unless (container = Module.const_lookup @root, container)
|
48
|
+
|
49
|
+
if dbm
|
50
|
+
accept = /#{dbm}/i
|
51
|
+
reject = nil
|
52
|
+
else
|
53
|
+
accept = nil
|
54
|
+
reject = /\b(#{DBMS.join('|')})/i
|
55
|
+
end
|
56
|
+
|
57
|
+
modules = []
|
58
|
+
modules += Module.descendants(container, can_load: accept)
|
59
|
+
modules.select!(&it.to_s =~ accept) if accept
|
60
|
+
modules.reject!(&it.to_s =~ reject) if reject
|
61
|
+
modules
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|