brick 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 580f34a900e392172361e334170169b30c63f83e96bd7b3119e9d957d440d6b1
4
- data.tar.gz: b02a7265b8010fe06d9599d353f7cdaf2435f872411fe8d6871fbd79e275ce19
3
+ metadata.gz: 1b4733a804fae7a4759eae48690541f1873cb81fd1b2a9986f849202c1c76c5d
4
+ data.tar.gz: d721f215cfed0473804f82969fd3c89dd7a94671d24b0f44b0e03cc73d787754
5
5
  SHA512:
6
- metadata.gz: '038902e9a8bc77505c28cf0038ff6aa77d0440f389bbc43b29ffaccae4e344e37d1d8fa7a683aae44c5c36d6b51f282fcd22174539c47c8f30e162b3e9dc71b9'
7
- data.tar.gz: f8e00496a7af527e47d75ef8a94cb02994224fa7fe536056b4399aac7758fdd3d3f3eddc364cbf6aec30efd4a56b852fa9982b7e06a48261a6bc9a178bc161fb
6
+ metadata.gz: b73c787a9c7aa6804d2cfce77921252dd77ce3e6e3710bd30875436d0f66011e6043e0ae4cbdaaeff6f4abb725d8051b5c1be139ee28b80648314f124ff7204f
7
+ data.tar.gz: 000b467728db85565d793df6e22429e3ff804bb7d39e5c4d6346becc24bc940ec9476fe00758d1e4a4fad868239e755ba7bdef596ecb115f358332656fd1be5e
data/lib/brick/config.rb CHANGED
@@ -20,6 +20,33 @@ module Brick
20
20
  @serializer = Brick::Serializers::YAML
21
21
  end
22
22
 
23
+ # Indicates whether Brick models are on or off. Default: true.
24
+ def enable_models
25
+ @mutex.synchronize { !!@enable_models }
26
+ end
27
+
28
+ def enable_models=(enable)
29
+ @mutex.synchronize { @enable_models = enable }
30
+ end
31
+
32
+ # Indicates whether Brick controllers are on or off. Default: true.
33
+ def enable_controllers
34
+ @mutex.synchronize { !!@enable_controllers }
35
+ end
36
+
37
+ def enable_controllers=(enable)
38
+ @mutex.synchronize { @enable_controllers = enable }
39
+ end
40
+
41
+ # Indicates whether Brick views are on or off. Default: true.
42
+ def enable_views
43
+ @mutex.synchronize { !!@enable_views }
44
+ end
45
+
46
+ def enable_views=(enable)
47
+ @mutex.synchronize { @enable_views = enable }
48
+ end
49
+
23
50
  # Indicates whether Brick routes are on or off. Default: true.
24
51
  def enable_routes
25
52
  @mutex.synchronize { !!@enable_routes }
@@ -28,5 +55,14 @@ module Brick
28
55
  def enable_routes=(enable)
29
56
  @mutex.synchronize { @enable_routes = enable }
30
57
  end
58
+
59
+ # Additional table associations to use (Think of these as virtual foreign keys perhaps)
60
+ def additional_references=(references)
61
+ @mutex.synchronize { @additional_references = references }
62
+ end
63
+
64
+ def additional_references
65
+ @mutex.synchronize { @additional_references }
66
+ end
31
67
  end
32
68
  end
@@ -28,57 +28,17 @@
28
28
 
29
29
  # Drag TmfModel#name onto the rows and have it automatically add five columns -- where type=zone / where type = sectionn / etc
30
30
 
31
-
32
- # ====================================
33
- # Dynamically create generic templates
34
- # ====================================
35
-
36
- # For templates:
37
- class ActionView::LookupContext
38
- alias :_brick_template_exists? :template_exists?
39
- def template_exists?(*args, **options)
40
- x = _brick_template_exists?(*args, **options)
41
- # Need to return true if we can fill in the blanks for a missing one
42
- # args will be something like: ["index", ["categories"]]
43
- unless x
44
- relations = Brick.instance_variable_get(:@relations)[ActiveRecord::Base.connection_pool.object_id] || {}
45
- matching = [views_name = args[1]&.first, views_name.singularize].find { |m| relations.key?(m) }
46
- if (x = matching && (matching = relations[matching]) &&
47
- (['index', 'show'].include?(args.first) || # Everything has index and show
48
- # Only CRU stuff has create / update / destroy
49
- (!matching.key?(:isView) && ['new', 'create', 'edit', 'update', 'destroy'].include?(args.first))
50
- )
51
- )
52
- instance_variable_set(:@_brick_match, matching)
53
- end
54
- end
55
- x
56
- end
57
-
58
- alias :_brick_find_template :find_template
59
- def find_template(*args, **options)
60
- if @_brick_match
61
- inline = case args.first
62
- when 'index'
63
- # Something like: <%= @categories.inspect %>
64
- "<%= @#{@_brick_match[:index]}.inspect %>"
65
- when 'show'
66
- "<%= @#{@_brick_match[:show]}.inspect %>"
67
- end
68
- # As if it were an inline template (see #determine_template in actionview-5.2.6.2/lib/action_view/renderer/template_renderer.rb)
69
- keys = options.has_key?(:locals) ? options[:locals].keys : []
70
- handler = ActionView::Template.handler_for_extension(options[:type] || 'erb')
71
- ActionView::Template.new(inline, "auto-generated #{args.first} template", handler, locals: keys)
72
- else
73
- _brick_find_template(*args, **options)
74
- end
75
- end
76
- end
77
-
78
31
  # ==========================================================
79
32
  # Dynamically create model or controller classes when needed
80
33
  # ==========================================================
81
34
 
35
+ # By default all models indicate that they are not views
36
+ class ActiveRecord::Base
37
+ def self.is_view?
38
+ false
39
+ end
40
+ end
41
+
82
42
  # Object.class_exec do
83
43
  class Object
84
44
  class << self
@@ -96,29 +56,28 @@ class Object
96
56
  # If the file really exists, go and snag it:
97
57
  return Object._brick_const_missing(*args) if ActiveSupport::Dependencies.search_for_file(class_name.underscore)
98
58
 
99
- if class_name.end_with?('Controller') && (plural_class_name = class_name[0..-11]).length.positive?
59
+ relations = ::Brick.instance_variable_get(:@relations)[ActiveRecord::Base.connection_pool.object_id] || {}
60
+ result = if ::Brick.enable_controllers? && class_name.end_with?('Controller') && (plural_class_name = class_name[0..-11]).length.positive?
100
61
  # Otherwise now it's up to us to fill in the gaps
101
- is_controller = true
102
- table_name = ActiveSupport::Inflector.underscore(plural_class_name)
103
- model_name = ActiveSupport::Inflector.singularize(plural_class_name)
104
- singular_table_name = ActiveSupport::Inflector.singularize(table_name)
105
- else # Model
62
+ if (model = ActiveSupport::Inflector.singularize(plural_class_name).constantize)
63
+ # if it's a controller and no match or a model doesn't really use the same table name, eager load all models and try to find a model class of the right name.
64
+ build_controller(class_name, plural_class_name, model, relations)
65
+ end
66
+ elsif ::Brick.enable_models?
106
67
  # See if a file is there in the same way that ActiveSupport::Dependencies#load_missing_constant
107
68
  # checks for it in ~/.rvm/gems/ruby-2.7.5/gems/activesupport-5.2.6.2/lib/active_support/dependencies.rb
108
69
  plural_class_name = ActiveSupport::Inflector.pluralize(model_name = class_name)
109
70
  singular_table_name = ActiveSupport::Inflector.underscore(model_name)
110
71
  table_name = ActiveSupport::Inflector.pluralize(singular_table_name)
72
+
73
+ # Maybe, just maybe there's a database table that will satisfy this need
74
+ if (matching = [table_name, singular_table_name, plural_class_name, model_name].find { |m| relations.key?(m) })
75
+ build_model(model_name, singular_table_name, table_name, relations, matching)
76
+ end
111
77
  end
112
- relations = Brick.instance_variable_get(:@relations)[ActiveRecord::Base.connection_pool.object_id] || {}
113
- # Maybe, just maybe there's a database table that will satisfy this need
114
- matches = [table_name, singular_table_name, plural_class_name, model_name]
115
- if matching = matches.find { |m| relations.key?(m) }
116
- built_class, code = if is_controller
117
- build_controller(class_name, model_name, singular_table_name, table_name, relations, matching)
118
- else
119
- build_model(model_name, singular_table_name, table_name, relations, matching)
120
- end
121
- puts "#{code}end # #{ is_controller ? 'controller' : 'model' }\n\n"
78
+ if result
79
+ built_class, code = result
80
+ puts "\n#{code}"
122
81
  built_class
123
82
  else
124
83
  puts "MISSING! #{args.inspect} #{table_name}"
@@ -131,7 +90,7 @@ class Object
131
90
  def build_model(model_name, singular_table_name, table_name, relations, matching)
132
91
  # Are they trying to use a pluralised class name such as "Employees" instead of "Employee"?
133
92
  if table_name == singular_table_name && !ActiveSupport::Inflector.inflections.uncountable.include?(table_name)
134
- raise NameError.new("Class name for a model that references table \"#{matching}\" should be \"#{ActiveSupport::Inflector.singularize(class_name)}\".")
93
+ raise NameError.new("Class name for a model that references table \"#{matching}\" should be \"#{ActiveSupport::Inflector.singularize(model_name)}\".")
135
94
  end
136
95
  code = +"class #{model_name} < ActiveRecord::Base\n"
137
96
  built_model = Class.new(ActiveRecord::Base) do |new_model_class|
@@ -139,11 +98,13 @@ class Object
139
98
  # Accommodate singular or camel-cased table names such as "order_detail" or "OrderDetails"
140
99
  code << " self.table_name = '#{self.table_name = matching}'\n" unless table_name == matching
141
100
 
142
- # By default, views get marked as read-only
143
- if (relation = relations[matching]).key?(:isView)
144
- self.define_method :'readonly?' do
101
+ # Override models backed by a view so they return true for #is_view?
102
+ # (Dynamically-created controllers and view templates for such models will then act in a read-only way)
103
+ if (is_view = (relation = relations[matching]).key?(:isView))
104
+ new_model_class.define_singleton_method :'is_view?' do
145
105
  true
146
106
  end
107
+ code << " def self.is_view?; true; end\n"
147
108
  end
148
109
 
149
110
  # Missing a primary key column? (Usually "id")
@@ -165,7 +126,7 @@ class Object
165
126
  code << " self.primary_key = #{pk_sym.inspect}\n"
166
127
  end
167
128
  else
168
- code << " # Could not identify any column(s) to use as a primary key\n"
129
+ code << " # Could not identify any column(s) to use as a primary key\n" unless is_view
169
130
  end
170
131
 
171
132
  # if relation[:cols].key?('last_update')
@@ -217,28 +178,31 @@ class Object
217
178
  end
218
179
  end
219
180
  end
181
+ code << "end # model #{model_name}\n\n"
220
182
  end # class definition
221
183
  [built_model, code]
222
184
  end
223
185
 
224
186
 
225
- def build_controller(class_name, model_name, singular_table_name, table_name, relations, matching)
187
+ def build_controller(class_name, plural_class_name, model, relations)
188
+ table_name = ActiveSupport::Inflector.underscore(plural_class_name)
189
+ singular_table_name = ActiveSupport::Inflector.singularize(table_name)
190
+
226
191
  code = +"class #{class_name} < ApplicationController\n"
227
192
  built_controller = Class.new(ActionController::Base) do |new_controller_class|
228
193
  Object.const_set(class_name.to_sym, new_controller_class)
229
194
 
230
- model = model_name.constantize
231
195
  code << " def index\n"
232
- code << " @#{table_name} = #{model_name}#{model.primary_key ? ".order(#{model.primary_key.inspect}" : '.all'})\n"
196
+ code << " @#{table_name} = #{model.name}#{model.primary_key ? ".order(#{model.primary_key.inspect}" : '.all'})\n"
233
197
  code << " end\n"
234
198
  self.define_method :index do
235
- relation = model.primary_key ? model.order(model.primary_key) : model.all
236
- instance_variable_set("@#{table_name}".to_sym, relation)
199
+ ar_relation = model.primary_key ? model.order(model.primary_key) : model.all
200
+ instance_variable_set("@#{table_name}".to_sym, ar_relation)
237
201
  end
238
202
 
239
203
  if model.primary_key
240
204
  code << " def show\n"
241
- code << " @#{singular_table_name} = #{model_name}.find(params[:id].split(','))\n"
205
+ code << " @#{singular_table_name} = #{model.name}.find(params[:id].split(','))\n"
242
206
  code << " end\n"
243
207
  self.define_method :show do
244
208
  instance_variable_set("@#{singular_table_name}".to_sym, model.find(params[:id].split(',')))
@@ -246,9 +210,11 @@ class Object
246
210
  end
247
211
 
248
212
  # By default, views get marked as read-only
249
- unless (relation = relations[matching]).key?(:isView)
213
+ unless (relation = relations[model.table_name]).key?(:isView)
250
214
  code << " # (Define :new, :create, :edit, :update, and :destroy)\n"
215
+ # Get column names for params from relations[model.table_name][:cols].keys
251
216
  end
217
+ code << "end # #{class_name}\n\n"
252
218
  end # class definition
253
219
  [built_controller, code]
254
220
  end
@@ -270,14 +236,10 @@ end
270
236
  module ActiveRecord::ConnectionHandling
271
237
  alias old_establish_connection establish_connection
272
238
  def establish_connection(*args)
273
- connections = Brick.instance_variable_get(:@relations) ||
274
- Brick.instance_variable_set(:@relations, (connections = {}))
275
239
  # puts connections.inspect
276
240
  x = old_establish_connection(*args)
277
- # Key our list of relations for this connection off of the connection pool's object_id
278
- relations = (connections[ActiveRecord::Base.connection_pool.object_id] ||= Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = {} } })
279
241
 
280
- if relations.empty?
242
+ if (relations = ::Brick.relations).empty?
281
243
  schema = 'public'
282
244
  puts ActiveRecord::Base.connection.execute("SELECT current_setting('SEARCH_PATH')").to_a.inspect
283
245
  sql = ActiveRecord::Base.send(:sanitize_sql_array, [
@@ -326,7 +288,7 @@ module ActiveRecord::ConnectionHandling
326
288
  end
327
289
 
328
290
  sql = ActiveRecord::Base.send(:sanitize_sql_array, [
329
- "SELECT kcu1.CONSTRAINT_NAME, kcu1.TABLE_NAME, kcu1.COLUMN_NAME, kcu2.TABLE_NAME
291
+ "SELECT kcu1.TABLE_NAME, kcu1.COLUMN_NAME, kcu2.TABLE_NAME, kcu1.CONSTRAINT_NAME
330
292
  FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS rc
331
293
  INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kcu1
332
294
  ON kcu1.CONSTRAINT_CATALOG = rc.CONSTRAINT_CATALOG
@@ -340,31 +302,8 @@ module ActiveRecord::ConnectionHandling
340
302
  WHERE kcu1.CONSTRAINT_SCHEMA = ? -- COALESCE(current_setting('SEARCH_PATH'), 'public')", schema
341
303
  # AND kcu2.TABLE_NAME = ?;", Apartment::Tenant.current, table_name
342
304
  ])
343
- ActiveRecord::Base.connection.execute(sql).values.each do |fk|
344
- bt_assoc_name = fk[2].underscore
345
- bt_assoc_name = bt_assoc_name[0..-4] if bt_assoc_name.end_with?('_id')
346
-
347
- bts = (relation = relations[fk[1]]).fetch(:fks) { relation[:fks] = {} }
348
- if (assoc_bt = bts[fk[0]])
349
- assoc_bt[:fk] = assoc_bt[:fk].is_a?(String) ? [assoc_bt[:fk], fk[2]] : assoc_bt[:fk].concat(fk[2])
350
- assoc_bt[:assoc_name] = "#{assoc_bt[:assoc_name]}_#{fk[2]}"
351
- else
352
- assoc_bt = bts[fk[0]] = { is_bt: true, fk: fk[2], assoc_name: bt_assoc_name, inverse_table: fk[3] }
353
- end
305
+ ActiveRecord::Base.connection.execute(sql).values.each { |fk| ::Brick._add_bt_and_hm(fk, relations) }
354
306
 
355
- hms = (relation = relations[fk[3]]).fetch(:fks) { relation[:fks] = {} }
356
- if (assoc_hm = hms[fk[0]])
357
- assoc_hm[:fk] = assoc_hm[:fk].is_a?(String) ? [assoc_hm[:fk], fk[2]] : assoc_hm[:fk].concat(fk[2])
358
- assoc_hm[:alternate_name] = "#{assoc_hm[:alternate_name]}_#{bt_assoc_name}" unless assoc_hm[:alternate_name] == bt_assoc_name
359
- assoc_hm[:inverse] = assoc_bt
360
- else
361
- assoc_hm = hms[fk[0]] = { is_bt: false, fk: fk[2], assoc_name: fk[1], alternate_name: bt_assoc_name, inverse_table: fk[1], inverse: assoc_bt }
362
- hm_counts = relation.fetch(:hm_counts) { relation[:hm_counts] = {} }
363
- hm_counts[fk[1]] = hm_counts.fetch(fk[1]) { 0 } + 1
364
- end
365
- assoc_bt[:inverse] = assoc_hm
366
- # hms[fk[0]] << { is_bt: false, fk: fk[2], assoc_name: fk[1], alternate_name: bt_assoc_name, inverse_table: fk[1] }
367
- end
368
307
  # Find associative tables that can be set up for has_many :through
369
308
  relations.each do |_key, tbl|
370
309
  tbl_cols = tbl[:cols].keys
@@ -406,12 +345,62 @@ module Brick
406
345
 
407
346
  private
408
347
 
409
- def _create_class()
410
- end
411
348
  end
412
349
  end # module Extensions
413
350
  # rubocop:enable Style/CommentedKeyword
414
351
 
352
+ def self._add_bt_and_hm(fk, relations = nil)
353
+ relations ||= ::Brick.relations
354
+ bt_assoc_name = fk[1].underscore
355
+ bt_assoc_name = bt_assoc_name[0..-4] if bt_assoc_name.end_with?('_id')
356
+
357
+ bts = (relation = relations.fetch(fk[0], nil))&.fetch(:fks) { relation[:fks] = {} }
358
+ hms = (relation = relations.fetch(fk[2], nil))&.fetch(:fks) { relation[:fks] = {} }
359
+
360
+ unless (cnstr_name = fk[3])
361
+ # For any appended references (those that come from config), arrive upon a definitely unique constraint name
362
+ cnstr_base = cnstr_name = "(brick) #{fk[0]}_#{fk[2]}"
363
+ cnstr_added_num = 1
364
+ cnstr_name = "#{cnstr_base}_#{cnstr_added_num += 1}" while bts&.key?(cnstr_name) || hms&.key?(cnstr_name)
365
+ missing = []
366
+ missing << fk[0] unless relations.key?(fk[0])
367
+ missing << fk[2] unless relations.key?(fk[2])
368
+ unless missing.empty?
369
+ tables = relations.reject { |k, v| v.fetch(:isView, nil) }.keys.sort
370
+ puts "Brick: Additional reference #{fk.inspect} refers to non-existent #{'table'.pluralize(missing.length)} #{missing.join(' and ')}. (Available tables include #{tables.join(', ')}.)"
371
+ return
372
+ end
373
+ unless (cols = relations[fk[0]][:cols]).key?(fk[1])
374
+ columns = cols.map { |k, v| "#{k} (#{v.first.split(' ').first})" }
375
+ puts "Brick: Additional reference #{fk.inspect} refers to non-existent column #{fk[1]}. (Columns present in #{fk[0]} are #{columns.join(', ')}.)"
376
+ return
377
+ end
378
+ if (redundant = bts.find{|k, v| v[:inverse][:inverse_table] == fk[0] && v[:fk] == fk[1] && v[:inverse_table] == fk[2] })
379
+ puts "Brick: Additional reference #{fk.inspect} is redundant and can be removed. (Already established by #{redundant.first}.)"
380
+ return
381
+ end
382
+ end
383
+
384
+ if (assoc_bt = bts[cnstr_name])
385
+ assoc_bt[:fk] = assoc_bt[:fk].is_a?(String) ? [assoc_bt[:fk], fk[1]] : assoc_bt[:fk].concat(fk[1])
386
+ assoc_bt[:assoc_name] = "#{assoc_bt[:assoc_name]}_#{fk[1]}"
387
+ else
388
+ assoc_bt = bts[cnstr_name] = { is_bt: true, fk: fk[1], assoc_name: bt_assoc_name, inverse_table: fk[2] }
389
+ end
390
+
391
+ if (assoc_hm = hms[cnstr_name])
392
+ assoc_hm[:fk] = assoc_hm[:fk].is_a?(String) ? [assoc_hm[:fk], fk[1]] : assoc_hm[:fk].concat(fk[1])
393
+ assoc_hm[:alternate_name] = "#{assoc_hm[:alternate_name]}_#{bt_assoc_name}" unless assoc_hm[:alternate_name] == bt_assoc_name
394
+ assoc_hm[:inverse] = assoc_bt
395
+ else
396
+ assoc_hm = hms[cnstr_name] = { is_bt: false, fk: fk[1], assoc_name: fk[0], alternate_name: bt_assoc_name, inverse_table: fk[0], inverse: assoc_bt }
397
+ hm_counts = relation.fetch(:hm_counts) { relation[:hm_counts] = {} }
398
+ hm_counts[fk[0]] = hm_counts.fetch(fk[0]) { 0 } + 1
399
+ end
400
+ assoc_bt[:inverse] = assoc_hm
401
+ # hms[cnstr_name] << { is_bt: false, fk: fk[1], assoc_name: fk[0], alternate_name: bt_assoc_name, inverse_table: fk[0] }
402
+ end
403
+
415
404
  # Rails < 4.0 doesn't have ActiveRecord::RecordNotUnique, so use the more generic ActiveRecord::ActiveRecordError instead
416
405
  ar_not_unique_error = ActiveRecord.const_defined?('RecordNotUnique') ? ActiveRecord::RecordNotUnique : ActiveRecord::ActiveRecordError
417
406
  class NoUniqueColumnError < ar_not_unique_error
@@ -7,13 +7,67 @@ module Brick
7
7
  # paths['app/models'] << 'lib/brick/frameworks/active_record/models'
8
8
  config.brick = ActiveSupport::OrderedOptions.new
9
9
  initializer 'brick.initialisation' do |app|
10
+ Brick.enable_models = app.config.brick.fetch(:enable_models, true)
11
+ Brick.enable_controllers = app.config.brick.fetch(:enable_controllers, true)
12
+
13
+ # ====================================
14
+ # Dynamically create generic templates
15
+ # ====================================
16
+ if (Brick.enable_views = app.config.brick.fetch(:enable_views, true))
17
+ ActionView::LookupContext.class_exec do
18
+ alias :_brick_template_exists? :template_exists?
19
+ def template_exists?(*args, **options)
20
+ unless (is_template_exists = _brick_template_exists?(*args, **options))
21
+ # Need to return true if we can fill in the blanks for a missing one
22
+ # args will be something like: ["index", ["categories"]]
23
+ model = args[1].map(&:camelize).join('::').singularize.constantize
24
+ if (
25
+ is_template_exists = model && (
26
+ ['index', 'show'].include?(args.first) || # Everything has index and show
27
+ # Only CRU stuff has create / update / destroy
28
+ (!model.is_view? && ['new', 'create', 'edit', 'update', 'destroy'].include?(args.first))
29
+ )
30
+ )
31
+ instance_variable_set(:@_brick_model, model)
32
+ end
33
+ end
34
+ is_template_exists
35
+ end
36
+
37
+ alias :_brick_find_template :find_template
38
+ def find_template(*args, **options)
39
+ if @_brick_model
40
+ inline = case args.first
41
+ when 'index'
42
+ # Something like: <%= @categories.inspect %>
43
+ "<%= @#{@_brick_model.name.underscore.pluralize}.inspect %>"
44
+ when 'show'
45
+ "<%= @#{@_brick_model.name.underscore}.inspect %>"
46
+ end
47
+ # As if it were an inline template (see #determine_template in actionview-5.2.6.2/lib/action_view/renderer/template_renderer.rb)
48
+ keys = options.has_key?(:locals) ? options[:locals].keys : []
49
+ handler = ActionView::Template.handler_for_extension(options[:type] || 'erb')
50
+ ActionView::Template.new(inline, "auto-generated #{args.first} template", handler, locals: keys)
51
+ else
52
+ _brick_find_template(*args, **options)
53
+ end
54
+ end
55
+ end
56
+ end
57
+
10
58
  # Auto-routing behaviour
11
59
  if (::Brick.enable_routes = app.config.brick.fetch(:enable_routes, true))
12
60
  ::Brick.append_routes
13
61
  end
14
- # Brick.enable_models = app.config.brick.fetch(:enable_models, true)
15
- # Brick.enable_controllers = app.config.brick.fetch(:enable_controllers, true)
16
- # Brick.enable_views = app.config.brick.fetch(:enable_views, true)
62
+ # Additional references (virtual foreign keys)
63
+ if (ars = (::Brick.additional_references = app.config.brick.fetch(:additional_references, nil)))
64
+ ars = ars.call if ars.is_a?(Proc)
65
+ ars = ars.to_a unless ars.is_a?(Array)
66
+ ars = [ars] unless ars.empty? || ars.first.is_a?(Array)
67
+ ars.each do |fk|
68
+ ::Brick._add_bt_and_hm(fk[0..2])
69
+ end
70
+ end
17
71
  end
18
72
  end
19
73
  end
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 0
8
+ TINY = 1
9
9
 
10
10
  # PRE is nil unless it's a pre-release (beta, RC, etc.)
11
11
  PRE = nil
data/lib/brick.rb CHANGED
@@ -90,19 +90,73 @@ module Brick
90
90
  end
91
91
  end
92
92
 
93
+ # All tables and views (what Postgres calls "relations" including column and foreign key info)
94
+ def relations
95
+ connections = Brick.instance_variable_get(:@relations) ||
96
+ Brick.instance_variable_set(:@relations, (connections = {}))
97
+ # Key our list of relations for this connection off of the connection pool's object_id
98
+ (connections[ActiveRecord::Base.connection_pool.object_id] ||= Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = {} } })
99
+ end
100
+
101
+ # Switches Brick auto-models on or off, for all threads
102
+ # @api public
103
+ def enable_models=(value)
104
+ Brick.config.enable_models = value
105
+ end
106
+
107
+ # Returns `true` if Brick models are on, `false` otherwise. This affects all
108
+ # threads. Enabled by default.
109
+ # @api public
110
+ def enable_models?
111
+ !!Brick.config.enable_models
112
+ end
113
+
114
+ # Switches Brick auto-controllers on or off, for all threads
115
+ # @api public
116
+ def enable_controllers=(value)
117
+ Brick.config.enable_controllers = value
118
+ end
119
+
120
+ # Returns `true` if Brick controllers are on, `false` otherwise. This affects all
121
+ # threads. Enabled by default.
122
+ # @api public
123
+ def enable_controllers?
124
+ !!Brick.config.enable_controllers
125
+ end
126
+
127
+ # Switches Brick auto-views on or off, for all threads
128
+ # @api public
129
+ def enable_views=(value)
130
+ Brick.config.enable_views = value
131
+ end
132
+
133
+ # Returns `true` if Brick views are on, `false` otherwise. This affects all
134
+ # threads. Enabled by default.
135
+ # @api public
136
+ def enable_views?
137
+ !!Brick.config.enable_views
138
+ end
139
+
93
140
  # Switches Brick auto-routes on or off, for all threads
94
141
  # @api public
95
142
  def enable_routes=(value)
96
143
  Brick.config.enable_routes = value
97
144
  end
98
145
 
99
- # Returns `true` if Brick routes are on, `false` otherwise. This is the
100
- # on/off switch that affects all threads. Enabled by default.
146
+ # Returns `true` if Brick routes are on, `false` otherwise. This affects all
147
+ # threads. Enabled by default.
101
148
  # @api public
102
149
  def enable_routes?
103
150
  !!Brick.config.enable_routes
104
151
  end
105
152
 
153
+ # Additional table associations to use (Think of these as virtual foreign keys perhaps)
154
+ # @api public
155
+ def additional_references=(value)
156
+ Brick.config.additional_references = value
157
+ end
158
+
159
+
106
160
  # Returns Brick's `::Gem::Version`, convenient for comparisons. This is
107
161
  # recommended over `::Brick::VERSION::STRING`.
108
162
  #
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brick
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorin Thwaits
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-12 00:00:00.000000000 Z
11
+ date: 2022-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord