pvincent
3 months ago
7 changed files with 104 additions and 142 deletions
-
25config/initializers/content_security_policy.rb
-
16config/initializers/inflections.rb
-
14config/initializers/monkey_patcher.rb
-
13config/initializers/permissions_policy.rb
-
3config/initializers/rails_live_reload.rb
-
155lib/hot/constants.rb
-
20lib/monkey_patches/rails_live_reload/watcher.rb
@ -1,25 +0,0 @@ |
|||||
# Be sure to restart your server when you modify this file. |
|
||||
|
|
||||
# Define an application-wide content security policy. |
|
||||
# See the Securing Rails Applications Guide for more information: |
|
||||
# https://guides.rubyonrails.org/security.html#content-security-policy-header |
|
||||
|
|
||||
# Rails.application.configure do |
|
||||
# config.content_security_policy do |policy| |
|
||||
# policy.default_src :self, :https |
|
||||
# policy.font_src :self, :https, :data |
|
||||
# policy.img_src :self, :https, :data |
|
||||
# policy.object_src :none |
|
||||
# policy.script_src :self, :https |
|
||||
# policy.style_src :self, :https |
|
||||
# # Specify URI for violation reports |
|
||||
# # policy.report_uri "/csp-violation-report-endpoint" |
|
||||
# end |
|
||||
# |
|
||||
# # Generate session nonces for permitted importmap, inline scripts, and inline styles. |
|
||||
# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } |
|
||||
# config.content_security_policy_nonce_directives = %w(script-src style-src) |
|
||||
# |
|
||||
# # Report violations without enforcing the policy. |
|
||||
# # config.content_security_policy_report_only = true |
|
||||
# end |
|
@ -1,16 +0,0 @@ |
|||||
# Be sure to restart your server when you modify this file. |
|
||||
|
|
||||
# Add new inflection rules using the following format. Inflections |
|
||||
# are locale specific, and you may define rules for as many different |
|
||||
# locales as you wish. All of these examples are active by default: |
|
||||
# ActiveSupport::Inflector.inflections(:en) do |inflect| |
|
||||
# inflect.plural /^(ox)$/i, "\\1en" |
|
||||
# inflect.singular /^(ox)en/i, "\\1" |
|
||||
# inflect.irregular "person", "people" |
|
||||
# inflect.uncountable %w( fish sheep ) |
|
||||
# end |
|
||||
|
|
||||
# These inflection rules are supported but not enabled by default: |
|
||||
# ActiveSupport::Inflector.inflections(:en) do |inflect| |
|
||||
# inflect.acronym "RESTful" |
|
||||
# end |
|
@ -1,14 +1,14 @@ |
|||||
return unless Rails.application.server? |
return unless Rails.application.server? |
||||
|
|
||||
puts 'MonkeyPatcher runs:' |
|
||||
|
# puts 'MonkeyPatcher runs:' |
||||
patches = Dir.glob(Rails.root.join('lib', 'monkey_patches', '**', '*.rb')) |
patches = Dir.glob(Rails.root.join('lib', 'monkey_patches', '**', '*.rb')) |
||||
patches.each do |file| |
patches.each do |file| |
||||
puts "🐵 patching... #{Pathname.new(file).relative_path_from Rails.root}" |
|
||||
|
# puts "🐵 patching... #{Pathname.new(file).relative_path_from Rails.root}" |
||||
require file |
require file |
||||
end |
end |
||||
|
|
||||
puts case patches.count |
|
||||
when 0 then 'No patch found' |
|
||||
when 1 then '1 successful patch applied' |
|
||||
else "#{patches.count} successful patches applied" |
|
||||
end |
|
||||
|
# puts case patches.count |
||||
|
# when 0 then 'No patch found' |
||||
|
# when 1 then '1 successful patch applied' |
||||
|
# else "#{patches.count} successful patches applied" |
||||
|
# end |
@ -1,13 +0,0 @@ |
|||||
# Be sure to restart your server when you modify this file. |
|
||||
|
|
||||
# Define an application-wide HTTP permissions policy. For further |
|
||||
# information see: https://developers.google.com/web/updates/2018/06/feature-policy |
|
||||
|
|
||||
# Rails.application.config.permissions_policy do |policy| |
|
||||
# policy.camera :none |
|
||||
# policy.gyroscope :none |
|
||||
# policy.microphone :none |
|
||||
# policy.usb :none |
|
||||
# policy.fullscreen :self |
|
||||
# policy.payment :self, "https://secure.example.com" |
|
||||
# end |
|
@ -1,101 +1,104 @@ |
|||||
require 'dotenv' |
require 'dotenv' |
||||
|
|
||||
# Hot Live Constants |
|
||||
module Hot::Constants |
|
||||
HOTENV = {} # rubocop:disable Style/MutableConstant |
|
||||
LISTENERS = {} # rubocop:disable Style/MutableConstant |
|
||||
LOGGER = SemanticLogger[self] |
|
||||
TOTO = 'titi' |
|
||||
|
|
||||
class << self |
|
||||
def initialize |
|
||||
@old_definitions = {} |
|
||||
@hot_definitions = {} |
|
||||
|
|
||||
load_definitions |
|
||||
load_values |
|
||||
end |
|
||||
|
module Hot |
||||
|
# Hot Live Constants |
||||
|
module Constants |
||||
|
include SemanticLogger::Loggable |
||||
|
HOTENV = {} # rubocop:disable Style/MutableConstant |
||||
|
LISTENERS = {} # rubocop:disable Style/MutableConstant |
||||
|
|
||||
|
class << self |
||||
|
def initialize |
||||
|
@old_definitions = {} |
||||
|
@hot_definitions = {} |
||||
|
|
||||
|
logger.level = :fatal |
||||
|
load_definitions |
||||
|
load_values |
||||
|
logger.level = :info |
||||
|
end |
||||
|
|
||||
def load_definitions |
|
||||
LOGGER.debug('--load_definitions3') |
|
||||
|
def load_definitions |
||||
|
logger.debug('--load_definitions3') |
||||
|
|
||||
new_definitions = Dotenv.parse('.env.sample') |
|
||||
|
new_definitions = Dotenv.parse('.env.sample') |
||||
|
|
||||
definitions_to_actualize = {} |
|
||||
@old_definitions.merge(new_definitions) do |key, old_value, new_value| |
|
||||
definitions_to_actualize[key] = new_value if new_value != old_value |
|
||||
end |
|
||||
definitions_to_actualize.each { |key, value| define_method(:actualize, key, value) } |
|
||||
|
definitions_to_actualize = {} |
||||
|
@old_definitions.merge(new_definitions) do |key, old_value, new_value| |
||||
|
definitions_to_actualize[key] = new_value if new_value != old_value |
||||
|
end |
||||
|
definitions_to_actualize.each { |key, value| define_method(:actualize, key, value) } |
||||
|
|
||||
|
@old_definitions = new_definitions |
||||
|
|
||||
@old_definitions = new_definitions |
|
||||
|
definitions_to_remove = @hot_definitions.except(*new_definitions.keys) |
||||
|
definitions_to_remove.each_pair do |key, dkey| |
||||
|
logger.info("remove method <#{dkey}>") |
||||
|
singleton_class.undef_method(dkey) |
||||
|
@hot_definitions.delete(key) |
||||
|
end |
||||
|
|
||||
definitions_to_remove = @hot_definitions.except(*new_definitions.keys) |
|
||||
definitions_to_remove.each_pair do |key, dkey| |
|
||||
LOGGER.info("remove method <#{dkey}>") |
|
||||
singleton_class.undef_method(dkey) |
|
||||
@hot_definitions.delete(key) |
|
||||
|
definitions_to_add = new_definitions.except(*@hot_definitions.keys) |
||||
|
definitions_to_add.each { |key, value| define_method(:add, key, value) } |
||||
end |
end |
||||
|
|
||||
definitions_to_add = new_definitions.except(*@hot_definitions.keys) |
|
||||
definitions_to_add.each { |key, value| define_method(:add, key, value) } |
|
||||
end |
|
||||
|
def load_values |
||||
|
logger.debug('--load_values') |
||||
|
|
||||
def load_values |
|
||||
LOGGER.debug('--load_values') |
|
||||
|
new_env = Dotenv.parse |
||||
|
constants_to_delete = HOTENV.except(*new_env.keys) |
||||
|
constants_to_delete.each do |name, _| |
||||
|
# FIXME: default should read default and type from @old_definitions |
||||
|
type, default = @old_definitions[name] |
||||
|
logger.info("constant <#{name}> reverts to default value <#{default}> of type <#{type}>") |
||||
|
end |
||||
|
|
||||
new_env = Dotenv.parse |
|
||||
constants_to_delete = HOTENV.except(*new_env.keys) |
|
||||
constants_to_delete.each do |name, _| |
|
||||
# FIXME: default should read default and type from @old_definitions |
|
||||
type, default = @old_definitions[name] |
|
||||
LOGGER.info("constant <#{name}> reverts to default value <#{default}> of type <#{type}>") |
|
||||
end |
|
||||
|
constants_to_add = new_env.except(*HOTENV.keys) |
||||
|
constants_to_add.each do |constant| |
||||
|
logger.info("constant to add <#{constant}>") |
||||
|
end |
||||
|
|
||||
constants_to_add = new_env.except(*HOTENV.keys) |
|
||||
constants_to_add.each do |constant| |
|
||||
LOGGER.info("constant to add <#{constant}>") |
|
||||
|
HOTENV.replace new_env |
||||
|
# LISTENERS.each_pair { |k, b| perform_change(k, b) } |
||||
end |
end |
||||
|
|
||||
HOTENV.replace new_env |
|
||||
# LISTENERS.each_pair { |k, b| perform_change(k, b) } |
|
||||
end |
|
||||
|
|
||||
def on_change(key, &block) |
|
||||
LISTENERS[key.downcase.to_sym] = block |
|
||||
perform_change(key, block) |
|
||||
end |
|
||||
|
def on_change(key, &block) |
||||
|
LISTENERS[key.downcase.to_sym] = block |
||||
|
perform_change(key, block) |
||||
|
end |
||||
|
|
||||
private |
|
||||
|
private |
||||
|
|
||||
def define_method(mode, key, value) |
|
||||
dkey = key.downcase |
|
||||
method = infer_method_from_value(value) |
|
||||
|
def define_method(mode, key, value) |
||||
|
dkey = key.downcase |
||||
|
method = infer_method_from_value(value) |
||||
|
|
||||
inferred_type = method.name.to_s.split('_')[1] |
|
||||
LOGGER.info("#{mode} method <#{dkey}> of type <#{inferred_type}> with default value <#{value}> ") |
|
||||
|
inferred_type = method.name.to_s.split('_')[1] |
||||
|
logger.info("#{mode} method <#{dkey}> of type <#{inferred_type}> with default value <#{value}> ") |
||||
|
|
||||
singleton_class.define_method(dkey) { method.call(key, value) } |
|
||||
@hot_definitions.store(key, dkey) |
|
||||
end |
|
||||
|
singleton_class.define_method(dkey) { method.call(key, value) } |
||||
|
@hot_definitions.store(key, dkey) |
||||
|
end |
||||
|
|
||||
def perform_change(key, block) |
|
||||
old_value = nil # TODO: remember last previous value |
|
||||
new_value = method(key).call |
|
||||
block.call(new_value, old_value) |
|
||||
end |
|
||||
|
def perform_change(key, block) |
||||
|
old_value = nil # TODO: remember last previous value |
||||
|
new_value = method(key).call |
||||
|
block.call(new_value, old_value) |
||||
|
end |
||||
|
|
||||
def load_boolean(key, default) = HOTENV.fetch(key, default).to_s.downcase == 'true' |
|
||||
def load_integer(key, default) = HOTENV.fetch(key, default).to_i |
|
||||
def load_string(key, default) = HOTENV.fetch(key, default) |
|
||||
|
def load_boolean(key, default) = HOTENV.fetch(key, default).to_s.downcase == 'true' |
||||
|
def load_integer(key, default) = HOTENV.fetch(key, default).to_i |
||||
|
def load_string(key, default) = HOTENV.fetch(key, default) |
||||
|
|
||||
def infer_method_from_value(value) |
|
||||
case value.downcase |
|
||||
when /^(true|false)$/ then method(:load_boolean) |
|
||||
when /^\d+$/ then method(:load_integer) |
|
||||
else method(:load_string) |
|
||||
|
def infer_method_from_value(value) |
||||
|
case value.downcase |
||||
|
when /^(true|false)$/ then method(:load_boolean) |
||||
|
when /^\d+$/ then method(:load_integer) |
||||
|
else method(:load_string) |
||||
|
end |
||||
end |
end |
||||
end |
end |
||||
end |
|
||||
|
|
||||
initialize # done once on first require, cause this is just a module (not a class!) |
|
||||
|
initialize # done once on first require, cause this is just a module (not a class!) |
||||
|
end |
||||
end |
end |
Write
Preview
Loading…
Cancel
Save
Reference in new issue