cockpit 0.0.1.5

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.
@@ -0,0 +1,55 @@
1
+ module Cockpit
2
+ # Represents the definition of a preference for a particular model
3
+ class Definition
4
+ # The data type for the content stored in this preference type
5
+ attr_reader :type
6
+
7
+ def initialize(name, *args) #:nodoc:
8
+ options = args.extract_options!
9
+
10
+ @type = args.first ? args.first.to_sym : :boolean
11
+
12
+ # Create a column that will be responsible for typecasting
13
+ @column = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, options[:default], @type == :any ? nil : @type.to_s)
14
+
15
+ @group_defaults = (options[:group_defaults] || {}).inject({}) do |defaults, (group, default)|
16
+ defaults[group.is_a?(Symbol) ? group.to_s : group] = type_cast(default)
17
+ defaults
18
+ end
19
+ end
20
+
21
+ # The name of the preference
22
+ def name
23
+ @column.name
24
+ end
25
+
26
+ # The default value to use for the preference in case none have been
27
+ # previously defined
28
+ def default_value(group = nil)
29
+ @group_defaults.include?(group) ? @group_defaults[group] : @column.default
30
+ end
31
+
32
+ # Determines whether column backing this preference stores numberic values
33
+ def number?
34
+ @column.number?
35
+ end
36
+
37
+ # Typecasts the value based on the type of preference that was defined.
38
+ # This uses ActiveRecord's typecast functionality so the same rules for
39
+ # typecasting a model's columns apply here.
40
+ def type_cast(value)
41
+ @type == :any ? value : @column.type_cast(value)
42
+ end
43
+
44
+ # Typecasts the value to true/false depending on the type of preference
45
+ def query(value)
46
+ if !(value = type_cast(value))
47
+ false
48
+ elsif number?
49
+ !value.zero?
50
+ else
51
+ !value.blank?
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,25 @@
1
+ class Hash
2
+ def recursively_symbolize_keys!
3
+ self.symbolize_keys!
4
+ self.values.each do |v|
5
+ if v.is_a? Hash
6
+ v.recursively_symbolize_keys!
7
+ elsif v.is_a? Array
8
+ v.recursively_symbolize_keys!
9
+ end
10
+ end
11
+ self
12
+ end
13
+ end
14
+
15
+ class Array
16
+ def recursively_symbolize_keys!
17
+ self.each do |item|
18
+ if item.is_a? Hash
19
+ item.recursively_symbolize_keys!
20
+ elsif item.is_a? Array
21
+ item.recursively_symbolize_keys!
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,44 @@
1
+ module Cockpit::Helper
2
+
3
+ # always returns either an array or a string
4
+ def c(*args)
5
+ options = args.extract_options!
6
+ result = args.collect {|i| Settings.get(i).value }
7
+ result = result.pop if result.length == 1
8
+ result.blank? ? nil : result.to_s
9
+ end
10
+
11
+ def setting_tag(tag)
12
+
13
+ end
14
+
15
+ def settings_tag(key, &block)
16
+ Settings(key).each_setting do |key, attributes, value|
17
+
18
+ end
19
+ end
20
+
21
+ def setting_value(value)
22
+ result = case value
23
+ when Proc
24
+ value.call
25
+ when Cockpit::TreeHash
26
+ value
27
+ else
28
+ value
29
+ end
30
+ end
31
+
32
+ def setting_options(attributes)
33
+ return {} unless (attributes.is_a?(Hash) && attributes[:options])
34
+ options = case attributes[:options]
35
+ when Proc
36
+ attributes[:options].call
37
+ else
38
+ attributes[:options]
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ ActionView::Base.send(:include, Cockpit::Helper) if defined?(ActionView)
@@ -0,0 +1,103 @@
1
+ module Cockpit
2
+ module Store
3
+ class Base
4
+ attr_accessor :configurable
5
+
6
+ def initialize(*args)
7
+ options = args.extract_options!
8
+ options.each do |k, v|
9
+ self.send("#{k.to_s}=", v) if self.respond_to?("#{k.to_s}=")
10
+ end
11
+ @configuration = args.first
12
+ end
13
+
14
+ def configuration
15
+ @configuration
16
+ end
17
+
18
+ def tree=(value)
19
+ @tree = value if value.is_a?(TreeHash)
20
+ @tree
21
+ end
22
+
23
+ def tree
24
+ @tree ||= TreeHash.new
25
+ end
26
+
27
+ def clear(options = {})
28
+ tree.each do |k, v|
29
+ tree.delete(k) unless (options[:except] && options[:except].include?(k.to_sym))
30
+ end
31
+ end
32
+
33
+ def get(path)
34
+ tree.get(path)
35
+ end
36
+ alias_method :[], :get
37
+
38
+ def get!(path)
39
+ result = get(path)
40
+ raise "'#{path.to_s}' was not in Config" if result.blank?
41
+ result
42
+ end
43
+
44
+ def set(value)
45
+ return unless value.is_a?(Hash)
46
+ value.each { |k,v| set_one(k, v) }
47
+ end
48
+
49
+ def set_one(key, value)
50
+ tree.set(key, value)
51
+ end
52
+
53
+ def set!(value)
54
+ result = set(value)
55
+ raise "'#{path.to_s}' was not set in Config" if result.blank?
56
+ result
57
+ end
58
+
59
+ def []=(key, value)
60
+ set_one(key => value)
61
+ end
62
+ end
63
+
64
+ class Memory < Base
65
+
66
+ end
67
+
68
+ class Database < Base
69
+
70
+ def clear(options = {})
71
+ configuration.setting_class.all.collect(&:destroy) if options[:hard] == true
72
+ super(options)
73
+ end
74
+
75
+ def find_or_create(key)
76
+ result = configuration.setting_class.find(key.to_s) rescue nil
77
+ result ||= configuration.setting_class.create(:key => key.to_s)
78
+ end
79
+
80
+ def set_one_with_database(key, value)
81
+ setting = find_or_create(key)
82
+ cast_as = (setting.cast_as || Cockpit.get_type(value)).to_s
83
+ attributes = {:value => value, :cast_as => cast_as}
84
+ attributes[:configurable] = self.configurable if self.configurable
85
+ setting.update_attributes(attributes)
86
+ set_one_without_database(key, Cockpit.type_cast(value, cast_as))
87
+ end
88
+ alias_method_chain :set_one, :database
89
+
90
+ def get(key)
91
+ result = super(key)
92
+ if result.blank? && setting = find_or_create(key)
93
+ set(key => setting.value)
94
+ result = super(key)
95
+ else
96
+
97
+ end
98
+ result
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,113 @@
1
+ # http://www.daniel-azuma.com/blog/view/z3bqa0t01uugg1/implementing_dsl_blocks
2
+ module Cockpit
3
+ class TreeHash < Hash
4
+
5
+ def initialize
6
+ block = Proc.new {|h,k| h[k] = TreeHash.new(&block)}
7
+ super &block
8
+ end
9
+
10
+ def value_type
11
+ has_key?(:type) ? self[:type] : :string
12
+ end
13
+
14
+ def each_setting(&block)
15
+ dup.each do |k, v|
16
+ atrib = Hash.new
17
+ if v.has_key?(:value)
18
+ value = clone(v[:value])
19
+ atrib = clone(v)
20
+ else
21
+ v.each do |k, sub_v|
22
+ atrib[k] = clone(v[k]) unless sub_v.is_a?(TreeHash)
23
+ end
24
+ value = clone(v)
25
+ end
26
+ yield(k.to_s, atrib, value) if block_given?
27
+ end
28
+ end
29
+
30
+ def dup
31
+ result = super
32
+ result.each do |k,v|
33
+ result[k] = v.dup if v.is_a?(TreeHash)
34
+ end
35
+ result
36
+ end
37
+
38
+ def children
39
+ hash = {}
40
+ each do |k, v|
41
+ hash[k] = v if v.is_a?(Hash)
42
+ end
43
+ hash
44
+ end
45
+
46
+ def get(key)
47
+ traverse(key)
48
+ end
49
+
50
+ def get_attribute(key, attribute)
51
+ get(key)[attribute.to_sym]
52
+ end
53
+
54
+ def set(key, value)
55
+ traverse(key, value)
56
+ end
57
+
58
+ def set_attribute(key, value)
59
+ traverse(key, value, false)
60
+ end
61
+
62
+ def set_attributes(hash)
63
+ hash.each { |k, v| set_attribute(k, v) }
64
+ self
65
+ end
66
+
67
+ def to_hash
68
+ hash = {}
69
+ self.each do |k, v|
70
+ hash[k] = v.is_a?(TreeHash) ? v.to_hash : v
71
+ end
72
+ hash
73
+ end
74
+
75
+ protected
76
+ def traverse(path, value = nil, as_node = true)
77
+ path = path.to_s.split('.')
78
+ child = path.pop.to_sym
79
+ parent = path.inject(self) { |h,k| h[k.to_sym] }
80
+ unless value.nil?
81
+ if as_node
82
+ if parent[child].has_key?(:type)
83
+ parent[child][:value] = Cockpit.type_cast(value, parent[child][:type])
84
+ else
85
+ parent[child][:value] = value
86
+ parent[child][:type] = Cockpit.get_type(value)
87
+ end
88
+ else
89
+ parent[child] = value
90
+ end
91
+ end
92
+ parent[child]
93
+ end
94
+
95
+ def method_missing(meth, *args, &block)
96
+ options = args.extract_options!
97
+ meth = meth.to_s.gsub("=", "").to_sym
98
+ if args.empty?
99
+ return self[meth] if self.has_key?(meth)
100
+ found = get(meth).set_attributes(options)
101
+ found = found.instance_eval(&block) if block_given?
102
+ found
103
+ else
104
+ get(meth).set_attributes({:type => Cockpit.get_type(args.first)}.merge(options).merge(:value => args.first))
105
+ end
106
+ end
107
+
108
+ private
109
+ def clone(object)
110
+ (object.respond_to?(:dup) ? object.dup : object) rescue object
111
+ end
112
+ end
113
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'cockpit'
@@ -0,0 +1,22 @@
1
+ begin
2
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
3
+ rescue ArgumentError
4
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
5
+ end
6
+
7
+ ActiveRecord::Base.configurations = true
8
+
9
+ ActiveRecord::Schema.define(:version => 1) do
10
+
11
+ create_table :settings, :force => true do |t|
12
+ t.string :key
13
+ t.string :value
14
+ t.string :cast_as
15
+ t.string :configurable_type
16
+ t.integer :configurable_id
17
+ end
18
+
19
+ create_table "users", :force => true do |t|
20
+ end
21
+
22
+ end
data/test/lib/user.rb ADDED
@@ -0,0 +1,8 @@
1
+ class User < ActiveRecord::Base
2
+ acts_as_configurable :settings do
3
+ name "Lance", :title => "First Name", :options => ["Lance", "Viatropos"]
4
+ favorite do
5
+ color "red"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,90 @@
1
+ require "rubygems"
2
+ require "ruby-debug"
3
+ gem 'test-unit'
4
+ require "test/unit"
5
+ require 'active_support'
6
+ require 'active_support/test_case'
7
+ require 'active_record'
8
+ require 'active_record/fixtures'
9
+ require 'shoulda'
10
+ require 'shoulda/active_record'
11
+
12
+ require File.dirname(__FILE__) + '/lib/database'
13
+
14
+ require File.expand_path(File.join(File.dirname(__FILE__), '/../lib/cockpit'))
15
+
16
+ require File.dirname(__FILE__) + '/lib/user'
17
+
18
+ ActiveRecord::Base.class_eval do
19
+ def self.detonate
20
+ all.map(&:destroy)
21
+ end
22
+ end
23
+
24
+ ActiveSupport::TestCase.class_eval do
25
+
26
+ def load_settings
27
+ Settings do
28
+ asset :title => "Asset (and related) Settings" do
29
+ thumb do
30
+ width 100, :tip => "Thumb's width"
31
+ height 100, :tip => "Thumb's height"
32
+ end
33
+ medium do
34
+ width 600, :tip => "Thumb's width"
35
+ height 250, :tip => "Thumb's height"
36
+ end
37
+ large do
38
+ width 600, :tip => "Large's width"
39
+ height 295, :tip => "Large's height"
40
+ end
41
+ end
42
+ authentication :title => "Authentication Settings" do
43
+ use_open_id true
44
+ use_oauth true
45
+ end
46
+ front_page do
47
+ slideshow_tag "slideshow"
48
+ slideshow_effect "fade"
49
+ end
50
+ page do
51
+ per_page 10
52
+ feed_per_page 10
53
+ end
54
+ people do
55
+ show_avatars true
56
+ default_avatar "/images/missing-person.png"
57
+ end
58
+ site do
59
+ title "Martini"
60
+ tagline "Developer Friendly, Client Ready Blog with Rails 3"
61
+ keywords "Rails 3, Heroku, JQuery, HTML 5, Blog Engine, CSS3"
62
+ copyright "© 2010 Viatropos. All rights reserved."
63
+ timezones :value => lambda { TimeZone.first }, :options => lambda { TimeZone.all }
64
+ date_format "%m %d, %Y"
65
+ time_format "%H"
66
+ week_starts_on "Monday", :options => ["Monday", "Sunday", "Friday"]
67
+ language "en-US", :options => ["en-US", "de"]
68
+ touch_enabled true
69
+ touch_as_subdomain false
70
+ google_analytics ""
71
+ teasers :title => "Teasers" do
72
+ disable false
73
+ left 1, :title => "Left Teaser"
74
+ right 2
75
+ center 3
76
+ end
77
+ main_quote 1
78
+ end
79
+ social do
80
+ facebook "http://facebook.com/viatropos"
81
+ twitter "http://twitter.com/viatropos"
82
+ email "lancejpollard@gmail.com"
83
+ end
84
+ s3 do
85
+ key "my_key"
86
+ secret "my_secret"
87
+ end
88
+ end
89
+ end
90
+ end