cockpit 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{MIT-LICENSE → MIT-LICENSE.markdown} +0 -0
- data/README.markdown +70 -47
- data/lib/cockpit.rb +1 -0
- data/lib/cockpit/core/definition.rb +187 -76
- data/lib/cockpit/core/global.rb +35 -0
- data/lib/cockpit/core/helpers.rb +12 -0
- data/lib/cockpit/core/include.rb +29 -74
- data/lib/cockpit/core/scope.rb +46 -0
- data/lib/cockpit/core/settings.rb +113 -74
- data/lib/cockpit/core/spec.rb +65 -0
- data/lib/cockpit/core/store.rb +34 -38
- data/lib/cockpit/stores/active_record.rb +128 -0
- data/lib/cockpit/stores/file_system.rb +11 -0
- data/lib/cockpit/stores/memory.rb +16 -0
- data/lib/cockpit/stores/mongo.rb +29 -0
- data/lib/cockpit/stores/redis.rb +11 -0
- metadata +16 -19
- data/Rakefile +0 -79
- data/lib/cockpit/core/definitions.rb +0 -55
- data/lib/cockpit/many/include.rb +0 -18
- data/lib/cockpit/many/settings.rb +0 -21
- data/lib/cockpit/moneta/active_record.rb +0 -120
- data/lib/cockpit/moneta/simple_active_record.rb +0 -93
- data/test/lib/database.rb +0 -22
- data/test/lib/user.rb +0 -10
- data/test/test_active_record.rb +0 -80
- data/test/test_helper.rb +0 -88
- data/test/test_mongo.rb +0 -82
- data/test/test_stores.rb +0 -125
@@ -1,55 +0,0 @@
|
|
1
|
-
module Cockpit
|
2
|
-
# settings have one direct definition and many child definitions
|
3
|
-
class Definitions < Hash
|
4
|
-
attr_accessor :name, :scope
|
5
|
-
|
6
|
-
def initialize(*args, &block)
|
7
|
-
define!(*args, &block)
|
8
|
-
end
|
9
|
-
|
10
|
-
def define!(*args, &block)
|
11
|
-
options = args.extract_options!
|
12
|
-
options[:store] ||= args.first
|
13
|
-
options.each do |k, v|
|
14
|
-
send("#{k}=", v) if respond_to?("#{k}=")
|
15
|
-
end
|
16
|
-
raise ArgumentError.new("pass a :name to Cockpit::Setting.define!") if self.name.blank?
|
17
|
-
if block_given?
|
18
|
-
self << Cockpit::Definition.define!(&block)
|
19
|
-
end
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
def <<(value)
|
24
|
-
([value] + self.values).flatten.uniq.each do |definition|
|
25
|
-
self.merge!(definition.keys)
|
26
|
-
end
|
27
|
-
self
|
28
|
-
end
|
29
|
-
|
30
|
-
def []=(key, value)
|
31
|
-
self << Cockpit::Definition.new(key, value) unless has_key?(key)
|
32
|
-
super(key.to_s, value)
|
33
|
-
end
|
34
|
-
|
35
|
-
def [](key)
|
36
|
-
super(key.to_s)
|
37
|
-
end
|
38
|
-
|
39
|
-
def to_hash
|
40
|
-
keys.inject({}) do |hash, key|
|
41
|
-
hash[key] = self[key].value
|
42
|
-
hash
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def method_missing(method, *args, &block)
|
47
|
-
if has_key?(method)
|
48
|
-
self[method]
|
49
|
-
else
|
50
|
-
super(method, *args, &block)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
data/lib/cockpit/many/include.rb
DELETED
@@ -1,18 +0,0 @@
|
|
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
|
@@ -1,21 +0,0 @@
|
|
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
|
@@ -1,120 +0,0 @@
|
|
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
|
@@ -1,93 +0,0 @@
|
|
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/test/lib/database.rb
DELETED
@@ -1,22 +0,0 @@
|
|
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 :context
|
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
DELETED
data/test/test_active_record.rb
DELETED
@@ -1,80 +0,0 @@
|
|
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
DELETED
@@ -1,88 +0,0 @@
|
|
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
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '/../lib/cockpit'))
|
14
|
-
require File.dirname(__FILE__) + '/lib/user'
|
15
|
-
|
16
|
-
class Object
|
17
|
-
include Cockpit
|
18
|
-
end
|
19
|
-
|
20
|
-
ActiveRecord::Base.class_eval do
|
21
|
-
def self.detonate
|
22
|
-
all.map(&:destroy)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
ActiveSupport::TestCase.class_eval do
|
27
|
-
|
28
|
-
def load_settings
|
29
|
-
Cockpit do
|
30
|
-
asset :title => "Asset (and related) Settings" do
|
31
|
-
thumb do
|
32
|
-
width 100, :tip => "Thumb's width"
|
33
|
-
height 100, :tip => "Thumb's height"
|
34
|
-
end
|
35
|
-
medium do
|
36
|
-
width 600, :tip => "Thumb's width"
|
37
|
-
height 250, :tip => "Thumb's height"
|
38
|
-
end
|
39
|
-
large do
|
40
|
-
width 600, :tip => "Large's width"
|
41
|
-
height 295, :tip => "Large's height"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
authentication :title => "Authentication Settings" do
|
45
|
-
use_open_id true
|
46
|
-
use_oauth true
|
47
|
-
end
|
48
|
-
front_page do
|
49
|
-
slideshow_tag "slideshow"
|
50
|
-
slideshow_effect "fade"
|
51
|
-
end
|
52
|
-
page do
|
53
|
-
per_page 10
|
54
|
-
feed_per_page 10
|
55
|
-
end
|
56
|
-
people do
|
57
|
-
show_avatars true
|
58
|
-
default_avatar "/images/missing-person.png"
|
59
|
-
end
|
60
|
-
site do
|
61
|
-
title "Martini"
|
62
|
-
tagline "Developer Friendly, Client Ready Blog with Rails 3"
|
63
|
-
keywords "Rails 3, Heroku, JQuery, HTML 5, Blog Engine, CSS3"
|
64
|
-
copyright "© 2010 Viatropos. All rights reserved."
|
65
|
-
timezones :value => lambda { TimeZone.first }, :options => lambda { TimeZone.all }
|
66
|
-
date_format "%m %d, %Y"
|
67
|
-
time_format "%H"
|
68
|
-
week_starts_on "Monday", :options => ["Monday", "Sunday", "Friday"]
|
69
|
-
language "en-US", :options => ["en-US", "de"]
|
70
|
-
touch_enabled true
|
71
|
-
touch_as_subdomain false
|
72
|
-
google_analytics ""
|
73
|
-
teasers :title => "Teasers" do
|
74
|
-
disable false
|
75
|
-
left 1, :title => "Left Teaser"
|
76
|
-
right 2
|
77
|
-
center 3
|
78
|
-
end
|
79
|
-
main_quote 1
|
80
|
-
end
|
81
|
-
social do
|
82
|
-
facebook "http://facebook.com/viatropos"
|
83
|
-
twitter "http://twitter.com/viatropos"
|
84
|
-
email "lancejpollard@gmail.com"
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|