Skip to content

Instantly share code, notes, and snippets.

@structuralartistry
Last active August 29, 2015 14:10
Show Gist options
  • Save structuralartistry/dc4b06dbfa75a1233f72 to your computer and use it in GitHub Desktop.
Save structuralartistry/dc4b06dbfa75a1233f72 to your computer and use it in GitHub Desktop.
Making constants consistent and mungeable in tests
# config/initializers/app_config.rb
APP_CONFIG = AppConfig.new(YAML.load_file("#{Rails.root}/config/application.yml")[Rails.env])
# then you have application.yml or whatever you want to call it:
# config/application.yml (or some better name)
development:
<<: *defaults
default_audio_file_format: m4a
media_path: 'public/media/development'
media_path_clips: 'public/media/development/clips'
staging:
...
production:
...
# usage
# when need a constant, just use:
APP_CONFIG.constant_name
# of course the above works only for top level in the yml but nested you can still get
APP_CONFIG.constant_tree_name[:sub_value_one][:sub_value_two]
# ... in fact I think we could also make this more 'treeable' and have it traverse the yml and actually give us nested objects with a little bit of work, like:
APP_CONFIG.constant_tree_name.sub_value_one.sub_value_two
# whats cool about this is that it not only makes constants more consistent and easily 'seeable' from one file (vs in the environment files), but it also (and this is why I started doing it this way), allows us to easily change constant values for testing:
APP_CONFIG.stub(:constant_name).and_return('blah')
# the app config class file
# lib/app_config.rb (or whatever)
# this creates a class which will take hash from yaml application.yml file and simulate an
# instance method for each top level setting... this facilitates stubbing in tests
# class << hsh; def []=(key,val); return 'xxxx'; end; end;
class AppConfig
def initialize(hash)
hash.stringify_keys!
# dynamic should be regular hash, updatable
@dynamic = hash['dynamic'] || {}
hash.delete('dynamic')
# static uses AppConfigHash so we can control the setter
freeze_hash(hash)
@settings = hash
end
def dynamic
@dynamic
end
private
def method_missing(meth, *args, &block)
return @settings[meth.to_s]
end
def freeze_hash(hash)
disable_hash_setter(hash)
hash.each do |key, value|
if hash[key].is_a?(Hash)
freeze_hash(value)
end
end
end
def disable_hash_setter(hash)
class << hash
def []=(key,val)
raise 'Can not overwrite non-dynamic AppConfig constant!'
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment