Cockpit

> Super DRY Settings for Ruby, Rails, and Sinatra Apps. Thin layer above wycat's [Moneta](http://github.com/wycats/moneta) for pluggable backend support. ## How it works You can define arbitrarily nested key/value pairs of any type, and customize them from an Admin panel or the terminal, and save them to the MySQL, MongoDB, Redis, or even a File. You define settings like this: settings = Cockpit "mongo" do site do title "My Site" time_zone lambda { "Hawaii" } feed do per_page 10 formats %w(rss atom) end end end That gives you [this data structure](http://gist.github.com/558480), which is accessed internally as a flat hash with keys like this: ["site.feed.formats", "site.time_zone", "site.feed.per_page", "site", "site.feed", "site.title"] ## Global and Instance Settings By default you will have 1 set of global settings, accessible via `Cockpit::Settings.root` which is populated in this call: Cockpit "mongo" do site do author "Lance" end end If you want to have settings encapsulated in an independent scope, you can just assign that to a variable: site_settings = Cockpit "mongo" do site do author "Lance" end end ## Associated Settings with Models You can also associate settings with any object (plain Object, ActiveRecord, MongoMapper::Document, etc.): class User < ActiveRecord::Base include Cockpit cockpit "mongo" do preferences do favorite_color "red" end settings do google_analytics "123123123" end end end And access them like this: user = User.new user.cockpit["settings.google_analytics"] #=> "123123123" user.cockpit["preferences.favorite_color"] = "green" ## Swappable Backend Thanks to the work behind Moneta, there's a clear interface to key/value stores (and some people have added ActiveRecord support which I've included in this). The current backends supported are these keys: - mongodb (or 'mongo') - redis - active_record - file - memory - yaml It should be easy enough to wrap the rest of the Moneta adapters. This is specified as the first DSL attribute: Cockpit "redis" do site do author "Lance" end end ## Use Cases This makes it really easy to edit random settings from an interface, such as an admin panel. Next goal is to add callbacks around save/destroy so you can run processes when settings are changed (such as changing your google_analytics, which would require re-rendering views if they were cached). The goal is to make this [enormous configuration dsl work](http://gist.github.com/558432), so I can define an entire site in a DSL. ### Other API Notes When you specify the DSL, that creates a flat tree of defaults, which aren't saved to the database. Then when you update the setting, it saves to the database, otherwise when the value is read and is null, it will use the default from the in-memory/dsl-defined tree. You can also associate a hash with each setting definition. This is great for say options, defaults, titles and tooltips, etc. Here's an example: Cockpit "active_record" do site do time_zones "MST", :options => Proc.new { TZInfo::Timezone.all.map(&:name) } end end assert_equal TZInfo::Timezone.all.map(&:name), Cockpit::Settings["site.time_zones"][:options].call And you can access the definition object directly: Cockpit::Settings.definition("site.time_zones").attributes[:options] ## Customizations Not yet implemented, just ideas. If you want to extend the Relationship model and reference that in your child/parent classes, you can do that like so: class Bookmark < ActsAsJoinable::Relationship; end class User < ActiveRecord::Base joins :posts, :as => :parent, :through => :bookmark end copyright [@viatropos](http://viatropos.com) 2010