brick 1.0.11 → 1.0.14

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 513e7f88a3dc5ac0f198308e3d82b6f3990af72d5b7b628d83863d887ab50ee2
4
- data.tar.gz: 845340d554fcfad33d1d841a3098fcf93aaae96dd426c17256cefbe103dd1997
3
+ metadata.gz: '09600b354a3f70f8680f3dd7a9be9349e6666c013c09a7c9a0dc240e811344ee'
4
+ data.tar.gz: 0f6ec90f3d38338797a10ec4fc338fae6fdea5b9fddb376c2044fe719afaaa8b
5
5
  SHA512:
6
- metadata.gz: 87f4c91911e83770c025c36945bec40c191b73a539a94bf5188738b01b516df0347f20f3710d9cca8f392dfcc32b2df68413309edddedc13dfff8d47ca99efa6
7
- data.tar.gz: e357a73bd2f5d6371a3d92344cd5635f458f332b2027d66851e068cd3f833f7fffd3ff6dc2a51d48bc2b9b9696d14a5ff999ea5a626341d14ff90286b4a19836
6
+ metadata.gz: 7189638a98c3899d49473a48638dce78da4ed109ed1d4a69185015f9b19428d658fa40ef0f70aa1652a478754b6c1b683a963424ec3e627c56e97b3c2528bba7
7
+ data.tar.gz: a843f0ec11b7e40bc4cf0a7387ab33e87edd4d9a36de1e24d10c899d969e148015da346fe7b7915f9ffd5a769818e8948de36beb1a368d38a6bb3ab3a97ca7c5
data/lib/brick/config.rb CHANGED
@@ -91,6 +91,14 @@ module Brick
91
91
  @mutex.synchronize { @model_descrips = descrips }
92
92
  end
93
93
 
94
+ def sti_namespace_prefixes
95
+ @mutex.synchronize { @sti_namespace_prefixes ||= {} }
96
+ end
97
+
98
+ def sti_namespace_prefixes=(prefixes)
99
+ @mutex.synchronize { @sti_namespace_prefixes = prefixes }
100
+ end
101
+
94
102
  def skip_database_views
95
103
  @mutex.synchronize { @skip_database_views }
96
104
  end
@@ -136,19 +136,67 @@ module ActiveRecord
136
136
 
137
137
  alias _brick_find_sti_class find_sti_class
138
138
  def find_sti_class(type_name)
139
- ::Brick.sti_models[type_name] = { base: self } unless type_name.blank?
140
- _brick_find_sti_class(type_name)
139
+ if ::Brick.sti_models.key?(type_name)
140
+ _brick_find_sti_class(type_name)
141
+ else
142
+ # This auto-STI is more of a brute-force approach, building modules where needed
143
+ # The more graceful alternative is the overload of ActiveSupport::Dependencies#autoload_module! found below
144
+ ::Brick.sti_models[type_name] = { base: self } unless type_name.blank?
145
+ module_prefixes = type_name.split('::')
146
+ module_prefixes.unshift('') unless module_prefixes.first.blank?
147
+ module_name = module_prefixes[0..-2].join('::')
148
+ if ::Brick.config.sti_namespace_prefixes&.key?(module_name) ||
149
+ ::Brick.config.sti_namespace_prefixes&.key?(module_name[2..-1]) # Take off the leading '::' and see if this matches
150
+ _brick_find_sti_class(type_name)
151
+ elsif File.exists?(candidate_file = Rails.root.join('app/models' + module_prefixes.map(&:underscore).join('/') + '.rb'))
152
+ _brick_find_sti_class(type_name) # Find this STI class normally
153
+ else
154
+ # Build missing prefix modules if they don't yet exist
155
+ this_module = Object
156
+ module_prefixes[1..-2].each do |module_name|
157
+ mod = if this_module.const_defined?(module_name)
158
+ this_module.const_get(module_name)
159
+ else
160
+ this_module.const_set(module_name.to_sym, Module.new)
161
+ end
162
+ end
163
+ # Build STI subclass and place it into the namespace module
164
+ this_module.const_set(module_prefixes.last.to_sym, klass = Class.new(self))
165
+ klass
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ module ActiveSupport::Dependencies
174
+ class << self
175
+ # %%% Probably a little more targeted than other approaches we've taken thusfar
176
+ # This happens before the whole parent check
177
+ alias _brick_autoload_module! autoload_module!
178
+ def autoload_module!(*args)
179
+ into, const_name, qualified_name, path_suffix = args
180
+ if (base_class = ::Brick.config.sti_namespace_prefixes&.fetch(into.name, nil)&.constantize)
181
+ ::Brick.sti_models[qualified_name] = { base: base_class }
182
+ # Build subclass and place it into the specially STI-namespaced module
183
+ into.const_set(const_name.to_sym, klass = Class.new(base_class))
184
+ # %%% used to also have: autoload_once_paths.include?(base_path) ||
185
+ autoloaded_constants << qualified_name unless autoloaded_constants.include?(qualified_name)
186
+ klass
187
+ else
188
+ _brick_autoload_module!(*args)
141
189
  end
142
190
  end
143
191
  end
144
192
  end
145
193
 
146
- # Object.class_exec do
147
194
  class Object
148
195
  class << self
149
196
  alias _brick_const_missing const_missing
150
197
  def const_missing(*args)
151
- return Object.const_get(args.first) if Object.const_defined?(args.first)
198
+ return self.const_get(args.first) if self.const_defined?(args.first)
199
+ return Object.const_get(args.first) if Object.const_defined?(args.first) unless self == Object
152
200
 
153
201
  class_name = args.first.to_s
154
202
  # See if a file is there in the same way that ActiveSupport::Dependencies#load_missing_constant
@@ -156,42 +204,58 @@ class Object
156
204
  # that is, checking #qualified_name_for with: from_mod, const_name
157
205
  # If we want to support namespacing in the future, might have to utilise something like this:
158
206
  # path_suffix = ActiveSupport::Dependencies.qualified_name_for(Object, args.first).underscore
159
- # return Object._brick_const_missing(*args) if ActiveSupport::Dependencies.search_for_file(path_suffix)
207
+ # return self._brick_const_missing(*args) if ActiveSupport::Dependencies.search_for_file(path_suffix)
160
208
  # If the file really exists, go and snag it:
161
- return Object._brick_const_missing(*args) if ActiveSupport::Dependencies.search_for_file(class_name.underscore)
209
+ if !(is_found = ActiveSupport::Dependencies.search_for_file(class_name.underscore)) && (filepath = self.name&.split('::'))
210
+ filepath = (filepath[0..-2] + [class_name]).join('/').underscore + '.rb'
211
+ end
212
+ if is_found
213
+ return self._brick_const_missing(*args)
214
+ elsif ActiveSupport::Dependencies.search_for_file(filepath) # Last-ditch effort to pick this thing up before we fill in the gaps on our own
215
+ my_const = parent.const_missing(class_name) # ends up having: MyModule::MyClass
216
+ return my_const
217
+ end
162
218
 
163
219
  relations = ::Brick.instance_variable_get(:@relations)[ActiveRecord::Base.connection_pool.object_id] || {}
164
- result = if ::Brick.enable_controllers? && class_name.end_with?('Controller') && (plural_class_name = class_name[0..-11]).length.positive?
165
- # Otherwise now it's up to us to fill in the gaps
166
- if (model = ActiveSupport::Inflector.singularize(plural_class_name).constantize)
167
- # 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.
168
- build_controller(class_name, plural_class_name, model, relations)
169
- end
170
- elsif ::Brick.enable_models?
171
- # See if a file is there in the same way that ActiveSupport::Dependencies#load_missing_constant
172
- # checks for it in ~/.rvm/gems/ruby-2.7.5/gems/activesupport-5.2.6.2/lib/active_support/dependencies.rb
173
- plural_class_name = ActiveSupport::Inflector.pluralize(model_name = class_name)
174
- singular_table_name = ActiveSupport::Inflector.underscore(model_name)
175
-
176
- # Adjust for STI if we know of a base model for the requested model name
177
- table_name = if (base_model = ::Brick.sti_models[model_name]&.fetch(:base, nil))
178
- base_model.table_name
179
- else
180
- ActiveSupport::Inflector.pluralize(singular_table_name)
181
- end
182
-
183
- # Maybe, just maybe there's a database table that will satisfy this need
184
- if (matching = [table_name, singular_table_name, plural_class_name, model_name].find { |m| relations.key?(m) })
185
- build_model(model_name, singular_table_name, table_name, relations, matching)
186
- end
187
- end
220
+ is_controllers_enabled = ::Brick.enable_controllers? || (ENV['RAILS_ENV'] || ENV['RACK_ENV']) == 'development'
221
+ result = if is_controllers_enabled && class_name.end_with?('Controller') && (plural_class_name = class_name[0..-11]).length.positive?
222
+ # Otherwise now it's up to us to fill in the gaps
223
+ if (model = ActiveSupport::Inflector.singularize(plural_class_name).constantize)
224
+ # 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.
225
+ build_controller(class_name, plural_class_name, model, relations)
226
+ end
227
+ elsif ::Brick.enable_models?
228
+ # See if a file is there in the same way that ActiveSupport::Dependencies#load_missing_constant
229
+ # checks for it in ~/.rvm/gems/ruby-2.7.5/gems/activesupport-5.2.6.2/lib/active_support/dependencies.rb
230
+ plural_class_name = ActiveSupport::Inflector.pluralize(model_name = class_name)
231
+ singular_table_name = ActiveSupport::Inflector.underscore(model_name)
232
+
233
+ # Adjust for STI if we know of a base model for the requested model name
234
+ table_name = if (base_model = ::Brick.sti_models[model_name]&.fetch(:base, nil))
235
+ base_model.table_name
236
+ else
237
+ ActiveSupport::Inflector.pluralize(singular_table_name)
238
+ end
239
+
240
+ # Maybe, just maybe there's a database table that will satisfy this need
241
+ if (matching = [table_name, singular_table_name, plural_class_name, model_name].find { |m| relations.key?(m) })
242
+ build_model(model_name, singular_table_name, table_name, relations, matching)
243
+ end
244
+ end
188
245
  if result
189
246
  built_class, code = result
190
247
  puts "\n#{code}"
191
248
  built_class
249
+ elsif ::Brick.config.sti_namespace_prefixes&.key?(class_name)
250
+ # binding.pry
251
+ # module_prefixes = type_name.split('::')
252
+ # path = self.name.split('::')[0..-2] + []
253
+ # module_prefixes.unshift('') unless module_prefixes.first.blank?
254
+ # candidate_file = Rails.root.join('app/models' + module_prefixes.map(&:underscore).join('/') + '.rb')
255
+ self._brick_const_missing(*args)
192
256
  else
193
257
  puts "MISSING! #{args.inspect} #{table_name}"
194
- Object._brick_const_missing(*args)
258
+ self._brick_const_missing(*args)
195
259
  end
196
260
  end
197
261
 
@@ -203,7 +267,8 @@ class Object
203
267
 
204
268
  # Are they trying to use a pluralised class name such as "Employees" instead of "Employee"?
205
269
  if table_name == singular_table_name && !ActiveSupport::Inflector.inflections.uncountable.include?(table_name)
206
- raise NameError.new("Class name for a model that references table \"#{matching}\" should be \"#{ActiveSupport::Inflector.singularize(model_name)}\".")
270
+ puts "Warning: Class name for a model that references table \"#{matching}\" should be \"#{ActiveSupport::Inflector.singularize(model_name)}\"."
271
+ return
207
272
  end
208
273
  if (base_model = ::Brick.sti_models[model_name]&.fetch(:base, nil))
209
274
  is_sti = true
@@ -8,9 +8,9 @@ module Brick
8
8
  config.brick = ActiveSupport::OrderedOptions.new
9
9
  ActiveSupport.on_load(:before_initialize) do |app|
10
10
  ::Brick.enable_models = app.config.brick.fetch(:enable_models, true)
11
- ::Brick.enable_controllers = app.config.brick.fetch(:enable_controllers, true)
12
- ::Brick.enable_views = app.config.brick.fetch(:enable_views, true)
13
- ::Brick.enable_routes = app.config.brick.fetch(:enable_routes, true)
11
+ ::Brick.enable_controllers = app.config.brick.fetch(:enable_controllers, false)
12
+ ::Brick.enable_views = app.config.brick.fetch(:enable_views, false)
13
+ ::Brick.enable_routes = app.config.brick.fetch(:enable_routes, false)
14
14
  ::Brick.skip_database_views = app.config.brick.fetch(:skip_database_views, false)
15
15
 
16
16
  # Specific database tables and views to omit when auto-creating models
@@ -37,7 +37,7 @@ module Brick
37
37
  # ====================================
38
38
  # Dynamically create generic templates
39
39
  # ====================================
40
- if ::Brick.enable_views?
40
+ if ::Brick.enable_views? || (ENV['RAILS_ENV'] || ENV['RACK_ENV']) == 'development'
41
41
  ActionView::LookupContext.class_exec do
42
42
  alias :_brick_template_exists? :template_exists?
43
43
  def template_exists?(*args, **options)
@@ -209,7 +209,11 @@ function changeout(href, param, value) {
209
209
  <% next if k == '#{pk}' || ::Brick.config.metadata_columns.include?(k) %>
210
210
  <td>
211
211
  <% if (bt = bts[k]) %>
212
- <%= bt_obj = bt[1].find_by(bt.last => val); link_to(bt_obj.brick_descrip, bt_obj) if bt_obj %>
212
+ <%# Instead of just 'bt_obj we have to put in all of this junk:
213
+ # send(\"#\{bt_obj_class = bt[1].name.underscore\}_path\".to_sym, bt_obj.send(bt[1].primary_key.to_sym))
214
+ # Otherwise we get stuff like:
215
+ # ActionView::Template::Error (undefined method `vehicle_path' for #<ActionView::Base:0x0000000033a888>) %>
216
+ <%= bt_obj = bt[1].find_by(bt.last => val); link_to(bt_obj.brick_descrip, send(\"#\{bt_obj_class = bt[1].name.underscore\}_path\".to_sym, bt_obj.send(bt[1].primary_key.to_sym))) if bt_obj %>
213
217
  <% else %>
214
218
  <%= val %>
215
219
  <% end %>
@@ -244,7 +248,7 @@ function changeout(href, param, value) {
244
248
  </th>
245
249
  <td>
246
250
  <% if (bt = bts[k]) %>
247
- <%= bt_obj = bt[1].find_by(bt.last => val); link_to(bt_obj.brick_descrip, bt_obj) if bt_obj %>
251
+ <%= bt_obj = bt[1].find_by(bt.last => val); link_to(bt_obj.brick_descrip, send(\"#\{bt_obj_class = bt[1].name.underscore\}_path\".to_sym, bt_obj.send(bt[1].primary_key.to_sym))) if bt_obj %>
248
252
  <% else %>
249
253
  <%= val %>
250
254
  <% end %>
@@ -279,7 +283,7 @@ function changeout(href, param, value) {
279
283
  end
280
284
  end
281
285
 
282
- if ::Brick.enable_routes?
286
+ if ::Brick.enable_routes? || (ENV['RAILS_ENV'] || ENV['RACK_ENV']) == 'development'
283
287
  ActionDispatch::Routing::RouteSet.class_exec do
284
288
  alias _brick_finalize_routeset! finalize!
285
289
  def finalize!(*args, **options)
@@ -5,7 +5,7 @@ module Brick
5
5
  module VERSION
6
6
  MAJOR = 1
7
7
  MINOR = 0
8
- TINY = 11
8
+ TINY = 14
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
@@ -228,6 +228,13 @@ module Brick
228
228
  Brick.config.model_descrips = descrips
229
229
  end
230
230
 
231
+ # Module prefixes to build out and associate with specific base STI models
232
+ # @api public
233
+ def sti_namespace_prefixes=(snp)
234
+ Brick.config.sti_namespace_prefixes = snp
235
+ end
236
+
237
+
231
238
  # Returns Brick's `::Gem::Version`, convenient for comparisons. This is
232
239
  # recommended over `::Brick::VERSION::STRING`.
233
240
  #
@@ -80,11 +80,13 @@ module Brick
80
80
  # # Settings for the Brick gem
81
81
  # # (By default this auto-creates models, controllers, views, and routes on-the-fly.)
82
82
 
83
- # # Normally these all start out as being enabled, but can be selectively disabled:
84
- # Brick.enable_routes = false
83
+ # # Normally all are enabled in development mode, and for security reasons only models are enabled in production
84
+ # # and test. This allows you to either (a) turn off models entirely, or (b) enable controllers, views, and routes
85
+ # # in production.
86
+ # Brick.enable_routes = true # Setting this to \"false\" will disable routes in development
85
87
  # Brick.enable_models = false
86
- # Brick.enable_controllers = false
87
- # Brick.enable_views = false
88
+ # Brick.enable_controllers = true # Setting this to \"false\" will disable controllers in development
89
+ # Brick.enable_views = true # Setting this to \"false\" will disable views in development
88
90
 
89
91
  # # By default models are auto-created for database views, and set to be read-only. This can be skipped.
90
92
  # Brick.skip_database_views = true
@@ -133,6 +135,11 @@ module Brick
133
135
  # # user, then you can use model_descrips like this, putting expressions with property references in square brackets:
134
136
  # Brick.model_descrips = { 'User' => '[profile.firstname] [profile.lastname]' }
135
137
 
138
+ # # Module prefixes to be built out and associated when new subclasses are requested for specific base STI models
139
+ # # (If this setting exists then only these subclasses will be honoured, and other requested )
140
+ # # The prefixed :: here on the sample module name LetterTemplates is optional. Used here for clarity.
141
+ # Brick.sti_namespace_prefixes = { '::LetterTemplates' => 'LetterTemplate' }
142
+
136
143
  # # If a default route is not supplied, Brick attempts to find the most \"central\" table and wires up the default
137
144
  # # route to go to the :index action for what would be a controller for that table. You can specify any controller
138
145
  # # name and action you wish in order to override this and have that be the default route when none other has been
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.11
4
+ version: 1.0.14
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-22 00:00:00.000000000 Z
11
+ date: 2022-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord