cockpit 0.0.1.7 → 0.1.1

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,148 @@
1
+ module Cockpit
2
+ # settings have one direct definition and many child proxy
3
+ class Settings
4
+ class << self
5
+ attr_accessor :definitions
6
+
7
+ # Cockpit::Settings.define!(:name => "root", :scope => "default")
8
+ def define!(*args, &block)
9
+ setting = Cockpit::Settings.new(*args, &block)
10
+ @root ||= setting
11
+ setting
12
+ end
13
+
14
+ def store
15
+ root.store
16
+ end
17
+
18
+ def store_type
19
+ @store_type ||= :memory
20
+ end
21
+
22
+ def definitions
23
+ @definitions ||= []
24
+ end
25
+
26
+ def definitions_for(name)
27
+ definitions.detect do |i|
28
+ i.name == name.to_s
29
+ end
30
+ end
31
+
32
+ def definitions_for?(name)
33
+ !definitions_for(name).blank?
34
+ end
35
+
36
+ def root
37
+ @root ||= Cockpit::Settings.new(:name => "root", :store => store_type, :scope => "default")
38
+ end
39
+
40
+ def [](key)
41
+ root[key]
42
+ end
43
+
44
+ def []=(key, value)
45
+ root[key] = value
46
+ end
47
+
48
+ def clear
49
+ root.clear
50
+ end
51
+
52
+ def default(key)
53
+ root.default(key)
54
+ end
55
+
56
+ def inspect
57
+ "Cockpit::Settings root: #{root.inspect}"
58
+ end
59
+ end
60
+
61
+ attr_accessor :name, :scope, :store, :record
62
+
63
+ # Settings.new(:store => :memory, :record => @user, :definitions => Settings.definitions.first)
64
+ def initialize(*args, &block)
65
+ options = args.extract_options!
66
+ options[:name] ||= "root"
67
+ options[:store] ||= args.first
68
+ options.each do |k, v|
69
+ send("#{k}=", v)
70
+ end
71
+ raise ArgumentError.new("pass in a :store to Cockpit::Settings") if self.store.nil?
72
+
73
+ args << options
74
+
75
+ if definition = self.class.definitions_for(options[:name])
76
+ definition.define!(*args, &block)
77
+ else
78
+ self.class.definitions << Cockpit::Definitions.new(*args, &block)
79
+ end
80
+ end
81
+
82
+ def store=(value)
83
+ @store = Cockpit::Store.new(name, value, record).adapter
84
+ end
85
+
86
+ def merge!(hash)
87
+ hash.each do |key, value|
88
+ self[key] = value
89
+ end
90
+ end
91
+
92
+ def keys
93
+ definitions.keys
94
+ end
95
+
96
+ def [](key)
97
+ self.store[key.to_s] || default(key.to_s)
98
+ end
99
+
100
+ def []=(key, value)
101
+ self.store[key.to_s] = value
102
+ end
103
+
104
+ def clear
105
+ self.store.clear
106
+ end
107
+
108
+ def has_key?(key)
109
+ !_definition(key).blank?
110
+ end
111
+
112
+ def default(key)
113
+ _definition(key).value
114
+ end
115
+
116
+ def definition(key)
117
+ _definition(key).dup
118
+ end
119
+
120
+ def to_hash
121
+ keys.inject({}) do |hash, key|
122
+ hash[key] = self[key]
123
+ hash
124
+ end
125
+ end
126
+
127
+ def roots
128
+ @roots ||= keys.select { |key| key !~ /\./ }
129
+ end
130
+
131
+ protected
132
+ def definitions
133
+ @definitions ||= self.class.definitions_for(self.name)
134
+ end
135
+
136
+ def _definition(key)
137
+ definitions[key.to_s]
138
+ end
139
+
140
+ def method_missing(method, *args, &block)
141
+ if has_key?(method)
142
+ definition(method)
143
+ else
144
+ super(method, *args, &block)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,51 @@
1
+ module Cockpit
2
+ class Store
3
+ class << self
4
+ attr_accessor :stores
5
+
6
+ def stores
7
+ @stores ||= {}
8
+ end
9
+
10
+ def adapter(store)
11
+ stores[store.name.to_s] ||= {}
12
+ # unless stores[store.name.to_s].has_key?(store.value.to_s)
13
+ require 'moneta'
14
+ stores[store.name.to_s][store.value.to_s] = case store.value.to_s
15
+ when "mongo", "mongodb"
16
+ require 'moneta/adapters/mongodb'
17
+ Moneta::Adapters::MongoDB.new(:collection => store.name)
18
+ when "active_record"
19
+ require File.dirname(__FILE__) + '/../moneta/active_record'
20
+ Moneta::Adapters::ActiveRecord.new(:record => store.scope)
21
+ when "file"
22
+ require 'moneta/adapters/basic_file'
23
+ Moneta::Adapters::BasicFile.new(:path => "./.cockpit")
24
+ when "redis"
25
+ require 'moneta/adapters/redis'
26
+ Moneta::Adapters::Redis.new
27
+ when "memory"
28
+ require 'moneta/adapters/memory'
29
+ Moneta::Adapters::Memory.new
30
+ when "yaml"
31
+ require 'moneta/adapters/yaml'
32
+ Moneta::Adapters::YAML.new
33
+ end
34
+ # end
35
+ stores[store.name.to_s][store.value.to_s]
36
+ end
37
+ end
38
+
39
+ attr_reader :name, :value, :scope
40
+
41
+ def initialize(name, value, scope = nil)
42
+ @name = name
43
+ @value = value
44
+ @scope = scope
45
+ end
46
+
47
+ def adapter
48
+ self.class.adapter(self)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,18 @@
1
+ module Cockpit
2
+ module Include
3
+ module ActiveRecord
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.send(:include, InstanceMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+
11
+ end
12
+
13
+ module InstanceMethods
14
+
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ module Cockpit
2
+ module Many
3
+ class Settings
4
+ class << self
5
+ def define(&block)
6
+ DefinedBy::DSL(&block).each do |key, value, dsl_block|
7
+
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ class Setting
14
+ attr_reader :definition
15
+
16
+ def method_name
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,120 @@
1
+ begin
2
+ require "active_record"
3
+ rescue LoadError
4
+ puts "You need the activerecord gem in order to use the ActiveRecord moneta store"
5
+ exit
6
+ end
7
+
8
+ class Object
9
+ unless respond_to?(:symbolize_keys)
10
+ def symbolize_keys
11
+
12
+ end
13
+ end
14
+ end
15
+
16
+ module Moneta
17
+ module Adapters
18
+ class ActiveRecord
19
+ class Store < ::ActiveRecord::Base
20
+ set_primary_key 'key'
21
+ set_table_name 'settings'
22
+ belongs_to :configurable, :polymorphic => true
23
+
24
+ def parsed_value
25
+ JSON.parse(value)['root']
26
+ end
27
+ end
28
+
29
+ def initialize(options = {})
30
+ @options = options
31
+ @configurable = options[:record]
32
+ @cache = []
33
+ #Store.establish_connection(@options[:connection] || raise("Must specify :connection"))
34
+ Store.set_table_name(@options[:table] || 'settings')
35
+ end
36
+
37
+ module Implementation
38
+ def key?(key)
39
+ !!self[key]
40
+ end
41
+
42
+ def has_key?(key)
43
+ key?(key)
44
+ end
45
+
46
+ def [](key)
47
+ record = find_record(key)
48
+ record ? record.parsed_value : nil
49
+ end
50
+
51
+ def []=(key, value)
52
+ record = find_record(key)
53
+ attributes = {:value => {'root' => value}.to_json}.merge(configurable_attributes)
54
+ if record
55
+ record.update_attributes!(attributes)
56
+ else
57
+ store = Store.new(attributes)
58
+ store.key = key
59
+ store.save!
60
+ @cache << store
61
+ end
62
+ end
63
+
64
+ def fetch(key, value = nil)
65
+ value ||= block_given? ? yield(key) : default # TODO: Shouldn't yield if key is present?
66
+ self[key] || value
67
+ end
68
+
69
+ def delete(key)
70
+ record = find_record(key)
71
+ if record
72
+ @cache.delete(record)
73
+ record.destroy
74
+ record.parsed_value
75
+ end
76
+ end
77
+
78
+ def store(key, value, options = {})
79
+ self[key] = value
80
+ end
81
+
82
+ def clear
83
+ #Store.delete_all
84
+ end
85
+
86
+ private
87
+ def find_record(key)
88
+ if record = @cache.detect { |i| i.key == key }
89
+ record
90
+ else
91
+ @cache = Store.all(:conditions => configurable_attributes)
92
+ Store.find_by_key(key, :conditions => configurable_attributes) rescue nil
93
+ end
94
+ end
95
+
96
+ def configurable_attributes
97
+ conditions = {}
98
+ if @configurable
99
+ conditions[:configurable_type] = @configurable.class.name
100
+ conditions[:configurable_id] = @configurable.id
101
+ else
102
+ conditions[:configurable_type] = nil
103
+ conditions[:configurable_id] = nil
104
+ end
105
+ conditions
106
+ end
107
+
108
+ end
109
+
110
+ # Unimplemented
111
+ module Expiration
112
+ def update_key(key, options)
113
+ end
114
+ end
115
+
116
+ include Implementation
117
+ include Expiration
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,93 @@
1
+ begin
2
+ require "active_record"
3
+ rescue LoadError
4
+ puts "You need the activerecord gem in order to use the ActiveRecord moneta store"
5
+ exit
6
+ end
7
+
8
+ class Object
9
+ unless respond_to?(:symbolize_keys)
10
+ def symbolize_keys
11
+
12
+ end
13
+ end
14
+ end
15
+
16
+ module Moneta
17
+ module Adapters
18
+ class SimpleActiveRecord
19
+ class Store < ::ActiveRecord::Base
20
+ set_primary_key 'key'
21
+ set_table_name 'settings'
22
+
23
+ def parsed_value
24
+ JSON.parse(value)['root']
25
+ end
26
+ end
27
+
28
+ def initialize(options = {})
29
+ @options = options
30
+ #Store.establish_connection(@options[:connection] || raise("Must specify :connection"))
31
+ Store.set_table_name(@options[:table] || 'settings')
32
+ end
33
+
34
+ module Implementation
35
+ def key?(key)
36
+ !!self[key]
37
+ end
38
+
39
+ def has_key?(key)
40
+ key?(key)
41
+ end
42
+
43
+ def [](key)
44
+ record = Store.find_by_key(key)
45
+ record ? record.parsed_value : nil
46
+ end
47
+
48
+ def []=(key, value)
49
+ record = Store.find_by_key(key)
50
+ if record
51
+ record.update_attributes!(:value => {'root' => value}.to_json)
52
+ else
53
+ store = Store.new
54
+ store.key = key
55
+ store.value = {'root' => value}.to_json
56
+ store.save!
57
+ end
58
+ end
59
+
60
+ def fetch(key, value = nil)
61
+ value ||= block_given? ? yield(key) : default # TODO: Shouldn't yield if key is present?
62
+ self[key] || value
63
+ end
64
+
65
+ def delete(key)
66
+ record = Store.find_by_key(key)
67
+ if record
68
+ record.destroy
69
+ record.parsed_value
70
+ end
71
+ end
72
+
73
+ def store(key, value, options = {})
74
+ self[key] = value
75
+ end
76
+
77
+ def clear
78
+ Store.delete_all
79
+ end
80
+
81
+ end
82
+
83
+ # Unimplemented
84
+ module Expiration
85
+ def update_key(key, options)
86
+ end
87
+ end
88
+
89
+ include Implementation
90
+ include Expiration
91
+ end
92
+ end
93
+ end
data/lib/cockpit.rb CHANGED
@@ -1,22 +1,16 @@
1
1
  require 'rubygems'
2
- require 'active_support'
3
- require 'active_record'
4
2
 
5
3
  this = File.expand_path(File.dirname(__FILE__))
6
- Dir["#{this}/cockpit/*"].each { |c| require c }
7
-
8
- class Settings
9
- include Cockpit::Configuration
10
- end
4
+ Dir["#{this}/cockpit/*"].each { |c| require c unless File.directory?(c) }
5
+ Dir["#{this}/cockpit/core/*"].each { |c| require c unless File.directory?(c) }
6
+ Dir["#{this}/cockpit/adapters/*"].each { |c| require c unless File.directory?(c) }
11
7
 
12
8
  ActiveRecord::Base.send(:include, Cockpit) if defined?(ActiveRecord::Base)
13
9
 
14
10
  def Settings(*args, &block)
15
- Settings.define!(*args, &block)
11
+ Cockpit::Settings.define!(*args, &block)
16
12
  end
17
13
 
18
14
  def Cockpit(*args, &block)
19
15
  Settings(*args, &block)
20
16
  end
21
-
22
- require File.expand_path("#{this}/../app/models/setting.rb")
data/test/lib/database.rb CHANGED
@@ -11,10 +11,9 @@ ActiveRecord::Schema.define(:version => 1) do
11
11
  create_table :settings, :force => true do |t|
12
12
  t.string :key
13
13
  t.string :value
14
- t.string :cast_as
14
+ t.string :context
15
15
  t.string :configurable_type
16
16
  t.integer :configurable_id
17
- t.string :context
18
17
  end
19
18
 
20
19
  create_table :users, :force => true do |t|
data/test/lib/user.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  class User < ActiveRecord::Base
2
- acts_as_configurable :settings do
3
- name "Lance", :title => "First Name", :options => ["Lance", "Viatropos"]
2
+ include Cockpit
3
+
4
+ cockpit "mongo" do
5
+ appelation "Lance", :title => "First Name", :options => ["Lance", "Viatropos"]
4
6
  favorite do
5
- color "red"
7
+ colors %w(red green blue)
6
8
  end
7
9
  end
8
10
  end
@@ -0,0 +1,80 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class ActiveRecordTest < ActiveSupport::TestCase
4
+
5
+ context "ActiveRecord" do
6
+
7
+ setup do
8
+ Cockpit :active_record do
9
+ site do
10
+ title "My Site"
11
+ time_zone lambda { "Hawaii" }
12
+ feed do
13
+ per_page 10
14
+ formats %w(rss atom)
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ should "retrieve default values" do
21
+ assert_equal "My Site", Cockpit::Settings.default("site.title")
22
+ end
23
+
24
+ should "define values at runtime" do
25
+ Cockpit::Settings["site.title"] = "New Site"
26
+ assert_equal "New Site", Cockpit::Settings["site.title"]
27
+ end
28
+
29
+ should "use moneta" do
30
+ assert Cockpit::Settings.store
31
+ Cockpit::Settings["site.title"] = "Another Site"
32
+ assert_equal "Another Site", Cockpit::Settings.store["site.title"]
33
+ # puts Moneta::Adapters::ActiveRecord::Store.all.inspect
34
+ end
35
+
36
+ context "instance" do
37
+ setup do
38
+ @settings = Cockpit::Settings.new(:store => :active_record, :name => "site-cache", :scope => "default") do
39
+ site "a site"
40
+ end
41
+ end
42
+
43
+ should "have an instance of setting" do
44
+ assert @settings
45
+ assert_equal "a site", @settings["site"]
46
+ class User < ::ActiveRecord::Base
47
+ cockpit :active_record do
48
+ author "Lance"
49
+ title do
50
+ last_name "Pollard"
51
+ end
52
+ end
53
+ end
54
+ assert_equal "Lance", User.cockpit["author"]
55
+ assert_equal "Pollard", User.cockpit["title.last_name"]
56
+
57
+ user = User.new
58
+ assert_equal "Lance", user.cockpit["author"]
59
+ assert_equal "Pollard", user.cockpit["title.last_name"]
60
+ end
61
+
62
+ should "be able to assiociate Proc and hash" do
63
+ require 'tzinfo'
64
+ @settings = Cockpit :active_record do
65
+ site do
66
+ time_zones "MST", :options => Proc.new { TZInfo::Timezone.all.map(&:name) }
67
+ end
68
+ end
69
+
70
+ assert_equal TZInfo::Timezone.all.map(&:name), @settings.definition("site.time_zones")[:options].call
71
+ end
72
+ end
73
+
74
+ teardown do
75
+ Cockpit::Settings.clear
76
+ end
77
+
78
+ end
79
+
80
+ end
data/test/test_helper.rb CHANGED
@@ -10,11 +10,13 @@ require 'shoulda'
10
10
  require 'shoulda/active_record'
11
11
 
12
12
  require File.dirname(__FILE__) + '/lib/database'
13
-
14
13
  require File.expand_path(File.join(File.dirname(__FILE__), '/../lib/cockpit'))
15
-
16
14
  require File.dirname(__FILE__) + '/lib/user'
17
15
 
16
+ class Object
17
+ include Cockpit
18
+ end
19
+
18
20
  ActiveRecord::Base.class_eval do
19
21
  def self.detonate
20
22
  all.map(&:destroy)
@@ -24,7 +26,7 @@ end
24
26
  ActiveSupport::TestCase.class_eval do
25
27
 
26
28
  def load_settings
27
- Settings do
29
+ Cockpit do
28
30
  asset :title => "Asset (and related) Settings" do
29
31
  thumb do
30
32
  width 100, :tip => "Thumb's width"
@@ -81,10 +83,6 @@ ActiveSupport::TestCase.class_eval do
81
83
  twitter "http://twitter.com/viatropos"
82
84
  email "lancejpollard@gmail.com"
83
85
  end
84
- s3 do
85
- key "my_key"
86
- secret "my_secret"
87
- end
88
86
  end
89
87
  end
90
88
  end
@@ -0,0 +1,82 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class MongoDBTest < ActiveSupport::TestCase
4
+
5
+ context "MongoDB" do
6
+
7
+ setup do
8
+ Cockpit "mongo" do
9
+ site do
10
+ title "My Site"
11
+ time_zone lambda { "Hawaii" }
12
+ feed do
13
+ per_page 10
14
+ formats %w(rss atom)
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ should "retrieve default values" do
21
+ assert_equal "My Site", Cockpit::Settings.default("site.title")
22
+ end
23
+
24
+ should "define default values at runtime" do
25
+ Cockpit::Settings["site.title"] = "New Site"
26
+ assert_equal "New Site", Cockpit::Settings.default("site.title")
27
+ assert_equal "New Site", Cockpit::Settings["site.title"]
28
+ end
29
+
30
+ should "use moneta" do
31
+ assert Cockpit::Settings.store
32
+ Cockpit::Settings["site.title"] = "Another Site"
33
+ assert_equal "Another Site", Cockpit::Settings.store["default.site.title"]
34
+ end
35
+
36
+ context "instance" do
37
+ setup do
38
+ @settings = Cockpit::Settings.new(:name => "site-cache", :scope => "default") do
39
+ site "a site"
40
+ end
41
+ end
42
+
43
+ should "have an instance of setting" do
44
+ assert @settings
45
+ assert_equal "a site", @settings["site"]
46
+ class User
47
+ cockpit do
48
+ author "Lance"
49
+ title do
50
+ last_name "Pollard"
51
+ end
52
+ end
53
+ end
54
+ assert_equal "Lance", User.cockpit["author"]
55
+ assert_equal "Pollard", User.cockpit["title.last_name"]
56
+
57
+ user = User.new
58
+ assert_equal "Lance", user.cockpit["author"]
59
+ assert_equal "Pollard", user.cockpit["title.last_name"]
60
+
61
+ settings = load_settings
62
+ end
63
+
64
+ should "be able to assiociate Proc and hash" do
65
+ require 'tzinfo'
66
+ @settings = Cockpit "mongo" do
67
+ site do
68
+ time_zones "MST", :options => Proc.new { TZInfo::Timezone.all.map(&:name) }
69
+ end
70
+ end
71
+
72
+ assert_equal TZInfo::Timezone.all.map(&:name), @settings.definition("site.time_zones")[:options].call
73
+ end
74
+ end
75
+
76
+ teardown do
77
+ Cockpit::Settings.clear
78
+ end
79
+
80
+ end
81
+
82
+ end