bcms_settings 0.0.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.
data/LICENSE.txt ADDED
@@ -0,0 +1,165 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
12
+
13
+ 0. Additional Definitions.
14
+
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
18
+
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, inline functions and templates
70
+ (ten or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are
74
+ covered by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ 0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ 1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License, and convey such a combined library under terms of your
134
+ choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based
137
+ on the Library, uncombined with any other library facilities,
138
+ conveyed under the terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it
141
+ is a work based on the Library, and explaining where to find the
142
+ accompanying uncombined form of the same work.
143
+
144
+ 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions
147
+ of the GNU Lesser General Public License from time to time. Such new
148
+ versions will be similar in spirit to the present version, but may
149
+ differ in detail to address new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the
152
+ Library as you received it specifies that a certain numbered version
153
+ of the GNU Lesser General Public License "or any later version"
154
+ applies to it, you have the option of following the terms and
155
+ conditions either of that published version or of any later version
156
+ published by the Free Software Foundation. If the Library as you
157
+ received it does not specify a version number of the GNU Lesser
158
+ General Public License, you may choose any version of the GNU Lesser
159
+ General Public License ever published by the Free Software Foundation.
160
+
161
+ If the Library as you received it specifies that a proxy can decide
162
+ whether future versions of the GNU Lesser General Public License shall
163
+ apply, that proxy's public statement of acceptance of any version is
164
+ permanent authorization for you to choose that version for the
165
+ Library.
data/README ADDED
@@ -0,0 +1,243 @@
1
+ == Welcome to Rails
2
+
3
+ Rails is a web-application framework that includes everything needed to create
4
+ database-backed web applications according to the Model-View-Control pattern.
5
+
6
+ This pattern splits the view (also called the presentation) into "dumb" templates
7
+ that are primarily responsible for inserting pre-built data in between HTML tags.
8
+ The model contains the "smart" domain objects (such as Account, Product, Person,
9
+ Post) that holds all the business logic and knows how to persist themselves to
10
+ a database. The controller handles the incoming requests (such as Save New Account,
11
+ Update Product, Show Post) by manipulating the model and directing data to the view.
12
+
13
+ In Rails, the model is handled by what's called an object-relational mapping
14
+ layer entitled Active Record. This layer allows you to present the data from
15
+ database rows as objects and embellish these data objects with business logic
16
+ methods. You can read more about Active Record in
17
+ link:files/vendor/rails/activerecord/README.html.
18
+
19
+ The controller and view are handled by the Action Pack, which handles both
20
+ layers by its two parts: Action View and Action Controller. These two layers
21
+ are bundled in a single package due to their heavy interdependence. This is
22
+ unlike the relationship between the Active Record and Action Pack that is much
23
+ more separate. Each of these packages can be used independently outside of
24
+ Rails. You can read more about Action Pack in
25
+ link:files/vendor/rails/actionpack/README.html.
26
+
27
+
28
+ == Getting Started
29
+
30
+ 1. At the command prompt, start a new Rails application using the <tt>rails</tt> command
31
+ and your application name. Ex: rails myapp
32
+ 2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
33
+ 3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!"
34
+ 4. Follow the guidelines to start developing your application
35
+
36
+
37
+ == Web Servers
38
+
39
+ By default, Rails will try to use Mongrel if it's are installed when started with script/server, otherwise Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails
40
+ with a variety of other web servers.
41
+
42
+ Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is
43
+ suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
44
+ getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
45
+ More info at: http://mongrel.rubyforge.org
46
+
47
+ Say other Ruby web servers like Thin and Ebb or regular web servers like Apache or LiteSpeed or
48
+ Lighttpd or IIS. The Ruby web servers are run through Rack and the latter can either be setup to use
49
+ FCGI or proxy to a pack of Mongrels/Thin/Ebb servers.
50
+
51
+ == Apache .htaccess example for FCGI/CGI
52
+
53
+ # General Apache options
54
+ AddHandler fastcgi-script .fcgi
55
+ AddHandler cgi-script .cgi
56
+ Options +FollowSymLinks +ExecCGI
57
+
58
+ # If you don't want Rails to look in certain directories,
59
+ # use the following rewrite rules so that Apache won't rewrite certain requests
60
+ #
61
+ # Example:
62
+ # RewriteCond %{REQUEST_URI} ^/notrails.*
63
+ # RewriteRule .* - [L]
64
+
65
+ # Redirect all requests not available on the filesystem to Rails
66
+ # By default the cgi dispatcher is used which is very slow
67
+ #
68
+ # For better performance replace the dispatcher with the fastcgi one
69
+ #
70
+ # Example:
71
+ # RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
72
+ RewriteEngine On
73
+
74
+ # If your Rails application is accessed via an Alias directive,
75
+ # then you MUST also set the RewriteBase in this htaccess file.
76
+ #
77
+ # Example:
78
+ # Alias /myrailsapp /path/to/myrailsapp/public
79
+ # RewriteBase /myrailsapp
80
+
81
+ RewriteRule ^$ index.html [QSA]
82
+ RewriteRule ^([^.]+)$ $1.html [QSA]
83
+ RewriteCond %{REQUEST_FILENAME} !-f
84
+ RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
85
+
86
+ # In case Rails experiences terminal errors
87
+ # Instead of displaying this message you can supply a file here which will be rendered instead
88
+ #
89
+ # Example:
90
+ # ErrorDocument 500 /500.html
91
+
92
+ ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
93
+
94
+
95
+ == Debugging Rails
96
+
97
+ Sometimes your application goes wrong. Fortunately there are a lot of tools that
98
+ will help you debug it and get it back on the rails.
99
+
100
+ First area to check is the application log files. Have "tail -f" commands running
101
+ on the server.log and development.log. Rails will automatically display debugging
102
+ and runtime information to these files. Debugging info will also be shown in the
103
+ browser on requests from 127.0.0.1.
104
+
105
+ You can also log your own messages directly into the log file from your code using
106
+ the Ruby logger class from inside your controllers. Example:
107
+
108
+ class WeblogController < ActionController::Base
109
+ def destroy
110
+ @weblog = Weblog.find(params[:id])
111
+ @weblog.destroy
112
+ logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
113
+ end
114
+ end
115
+
116
+ The result will be a message in your log file along the lines of:
117
+
118
+ Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1
119
+
120
+ More information on how to use the logger is at http://www.ruby-doc.org/core/
121
+
122
+ Also, Ruby documentation can be found at http://www.ruby-lang.org/ including:
123
+
124
+ * The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
125
+ * Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
126
+
127
+ These two online (and free) books will bring you up to speed on the Ruby language
128
+ and also on programming in general.
129
+
130
+
131
+ == Debugger
132
+
133
+ Debugger support is available through the debugger command when you start your Mongrel or
134
+ Webrick server with --debugger. This means that you can break out of execution at any point
135
+ in the code, investigate and change the model, AND then resume execution!
136
+ You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'
137
+ Example:
138
+
139
+ class WeblogController < ActionController::Base
140
+ def index
141
+ @posts = Post.find(:all)
142
+ debugger
143
+ end
144
+ end
145
+
146
+ So the controller will accept the action, run the first line, then present you
147
+ with a IRB prompt in the server window. Here you can do things like:
148
+
149
+ >> @posts.inspect
150
+ => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
151
+ #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
152
+ >> @posts.first.title = "hello from a debugger"
153
+ => "hello from a debugger"
154
+
155
+ ...and even better is that you can examine how your runtime objects actually work:
156
+
157
+ >> f = @posts.first
158
+ => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
159
+ >> f.
160
+ Display all 152 possibilities? (y or n)
161
+
162
+ Finally, when you're ready to resume execution, you enter "cont"
163
+
164
+
165
+ == Console
166
+
167
+ You can interact with the domain model by starting the console through <tt>script/console</tt>.
168
+ Here you'll have all parts of the application configured, just like it is when the
169
+ application is running. You can inspect domain models, change values, and save to the
170
+ database. Starting the script without arguments will launch it in the development environment.
171
+ Passing an argument will specify a different environment, like <tt>script/console production</tt>.
172
+
173
+ To reload your controllers and models after launching the console run <tt>reload!</tt>
174
+
175
+ == dbconsole
176
+
177
+ You can go to the command line of your database directly through <tt>script/dbconsole</tt>.
178
+ You would be connected to the database with the credentials defined in database.yml.
179
+ Starting the script without arguments will connect you to the development database. Passing an
180
+ argument will connect you to a different database, like <tt>script/dbconsole production</tt>.
181
+ Currently works for mysql, postgresql and sqlite.
182
+
183
+ == Description of Contents
184
+
185
+ app
186
+ Holds all the code that's specific to this particular application.
187
+
188
+ app/controllers
189
+ Holds controllers that should be named like weblogs_controller.rb for
190
+ automated URL mapping. All controllers should descend from ApplicationController
191
+ which itself descends from ActionController::Base.
192
+
193
+ app/models
194
+ Holds models that should be named like post.rb.
195
+ Most models will descend from ActiveRecord::Base.
196
+
197
+ app/views
198
+ Holds the template files for the view that should be named like
199
+ weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby
200
+ syntax.
201
+
202
+ app/views/layouts
203
+ Holds the template files for layouts to be used with views. This models the common
204
+ header/footer method of wrapping views. In your views, define a layout using the
205
+ <tt>layout :default</tt> and create a file named default.html.erb. Inside default.html.erb,
206
+ call <% yield %> to render the view using this layout.
207
+
208
+ app/helpers
209
+ Holds view helpers that should be named like weblogs_helper.rb. These are generated
210
+ for you automatically when using script/generate for controllers. Helpers can be used to
211
+ wrap functionality for your views into methods.
212
+
213
+ config
214
+ Configuration files for the Rails environment, the routing map, the database, and other dependencies.
215
+
216
+ db
217
+ Contains the database schema in schema.rb. db/migrate contains all
218
+ the sequence of Migrations for your schema.
219
+
220
+ doc
221
+ This directory is where your application documentation will be stored when generated
222
+ using <tt>rake doc:app</tt>
223
+
224
+ lib
225
+ Application specific libraries. Basically, any kind of custom code that doesn't
226
+ belong under controllers, models, or helpers. This directory is in the load path.
227
+
228
+ public
229
+ The directory available for the web server. Contains subdirectories for images, stylesheets,
230
+ and javascripts. Also contains the dispatchers and the default HTML files. This should be
231
+ set as the DOCUMENT_ROOT of your web server.
232
+
233
+ script
234
+ Helper scripts for automation and generation.
235
+
236
+ test
237
+ Unit and functional tests along with fixtures. When using the script/generate scripts, template
238
+ test files will be generated for you and placed in this directory.
239
+
240
+ vendor
241
+ External libraries that the application depends on. Also includes the plugins subdirectory.
242
+ If the app has frozen rails, those gems also go here, under vendor/rails/.
243
+ This directory is in the load path.
@@ -0,0 +1,10 @@
1
+ # Filters added to this controller apply to all controllers in the application.
2
+ # Likewise, all the methods added will be available for all controllers.
3
+
4
+ class ApplicationController < ActionController::Base
5
+ helper :all # include all helpers, all the time
6
+ protect_from_forgery # See ActionController::RequestForgeryProtection for details
7
+
8
+ # Scrub sensitive parameters from your log
9
+ # filter_parameter_logging :password
10
+ end
@@ -0,0 +1,3 @@
1
+ # Methods added to this helper will be available to all templates in the application.
2
+ module ApplicationHelper
3
+ end
@@ -0,0 +1,19 @@
1
+
2
+ # CmsModule objects represent bcms modules registered with the Cms:Settings module.
3
+ # These objects are not ment to be accessed directly, but through Cms:Settings'
4
+ # public interface.
5
+
6
+ class CmsModule < ActiveRecord::Base
7
+
8
+ NAME_REGEX = /^bcms_[a-z0-9_]+/
9
+
10
+ validates_uniqueness_of :name
11
+ validates_presence_of :name
12
+ validates_format_of :name, :with => NAME_REGEX
13
+
14
+ serialize :settings
15
+
16
+ named_scope :managed, :conditions => {:cms_managed => true},
17
+ :select => 'name'
18
+ end
19
+
@@ -0,0 +1,14 @@
1
+ class CreateCmsModules < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :cms_modules do |t|
4
+ t.string :name, :limit => 50
5
+ t.text :settings
6
+ t.boolean :cms_managed, :default => true
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :cms_modules
12
+ end
13
+ end
14
+
@@ -0,0 +1,2 @@
1
+ Use this README file to introduce your application and point to useful places in the API for learning more.
2
+ Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
@@ -0,0 +1,2 @@
1
+ require 'bcms_settings/routes'
2
+ require 'bcms_settings/cms/settings'
@@ -0,0 +1,265 @@
1
+ module Cms
2
+ # Cms::Settings provides an interface for storing and retrieving
3
+ # arbitrary key value pairs and can be used as a persistent
4
+ # global configuration store.
5
+ #
6
+ # Cms::Settings stores key value pairs in attributes of ActiveRecord
7
+ # objects. These objects, however, are not designed to be used
8
+ # directly. Rather, this module provides an interface for easy
9
+ # access to the storage objects.
10
+ #
11
+ # For all installed bcms modules loaded as gems as defined by the BrowserCMS'
12
+ # module instalation process, this module creates a namespaced key value
13
+ # store automatically.
14
+ #
15
+ # To know which bcms_modules the Settings module knows about:
16
+ # Cms::Settings.modules => [] #an empty array for new projects.
17
+ #
18
+ # If a BrowserCMS project declares the following gem dependencies
19
+ # in environment.rb:
20
+ #
21
+ # gem.bcms_s3
22
+ # gem.bcms_seo_sitemap
23
+ #
24
+ # Client code can access the following objects automatically:
25
+ #
26
+ # Cms::Settings.bcms_s3 => #<Cms::Settings: bcms_s3 => {}>
27
+ # Cms::Settings.bcms_seo_sitemap => #<Cms::Settings: bcms_seo_sitemap => {}>
28
+ #
29
+ # To store key, value pairs just call an "=" method with an arbitrary name
30
+ # and value:
31
+ #
32
+ # Cms::Settings.bcms_s3.account_id = "ACCOUNT_ID"
33
+ # Cms::Settings.bcms_s3.buckets = %w[bucket1 bucket2]
34
+ #
35
+ # After adding these two values, the object looks like this:
36
+ #
37
+ # Cms::Settings.bcms_s3 => <Cms::Settings: bcms_s3 => {"account_id"=>"ACCOUNT_ID", "buckets"=>["bucket1", "bucket2"]}>
38
+ #
39
+ # To retrieve values:
40
+ #
41
+ # Cms::Settings.bcms_s3.account_id => "ACCOUNT_ID"
42
+ # Cms::Settings.bcms_s3.buckets.first = "bucket1"
43
+ #
44
+ # To update keys, just assign new values:
45
+ #
46
+ # Cms::Settings.bcms_s3.account_id = "NEW_ID"
47
+ # Cms::Settings.bcms_s3.account_id => "NEW_ID"
48
+ #
49
+ # To delete values, call the delete method on the settings object:
50
+ #
51
+ # Cms::Settings.bcms_s3.delete("buckets")
52
+ # Cms::Settings.bcms_s3 => #<Cms::Settings: bcms_s3 => {"account_id"=>"NEW_ID"}
53
+ #
54
+ # Keys can have almost any name, except:
55
+ # ["inspect", "__send__", "delete", "instance_eval", "__metaclass__", "method_missing", "__id__"]
56
+
57
+ module Settings
58
+
59
+ # Raised when an attempt is made to access configuration for a module
60
+ # that has not been previously registered or is not installed.
61
+ class ModuleNotRegistered < StandardError; end
62
+
63
+ # Raised when an attempt is made to register a moudle that has already
64
+ # been registered.
65
+ class ModuleConfigurationExists < StandardError; end
66
+
67
+ # Raised when a module name is not a valid BrowserCMS module name.
68
+ # All module names must be lowercase, start with the bcms_ prefix and
69
+ # must not contain whitespace or special characters. (Must be valid
70
+ # Ruby method identifiers).
71
+ #
72
+ # Although the CmsModule model class validates module names, the Settings
73
+ # module checks all names before passing them to the CmsModule and raises
74
+ # this exception right away.
75
+ class InvalidModuleName < StandardError; end
76
+
77
+ extend self
78
+
79
+ # cms managed modules are those that are declared as dependencies on
80
+ # environment.rb. The synchronize method keeps these installed modules
81
+ # in sync with the database automatically, creating a record for declared
82
+ # dependencies and deleting records for bcms_modules that are no longer
83
+ # installed.
84
+ #
85
+ # Cms::Settings.synchronize can be called as part of BrowserCMS'
86
+ # initialization process.
87
+ #
88
+ # If this method is never called, there won't be any cms managed 'automatic'
89
+ # modules, in which case all modules must register themselves calling
90
+ # Cms::Settings.register("bcms_xyz")
91
+ #`
92
+ # Conversely, if this method is called, all installed bcms modules will
93
+ # get a configuration object whether they need it or not.
94
+
95
+ def synchronize
96
+ register_modules(installed_modules - registered_modules)
97
+ remove_modules(managed_modules - installed_modules)
98
+ end
99
+
100
+ # Retruns an array of module names the Cms::Settings module knows
101
+ # about.
102
+ #
103
+ # [in environment.rb]
104
+ # gem.bcms_s3
105
+ # gem.bcms_news
106
+ #
107
+ # Cms::Settings.modules => ["bcms_s3", "bcms_news"]
108
+ # Cms::Settings.register("bcms_blog")
109
+ # Cms::Settings.modules => ["bcms_s3", "bcms_news", "bcms_blog"]
110
+
111
+ def modules
112
+ registered_modules
113
+ end
114
+
115
+ # Manually registered modules are ignored by the synchronize method.
116
+ #
117
+ # Cms::Settings.register("bcms_foo")
118
+ # Cms::Settings.bcms_foo will be prsisted in the thatabase until
119
+ # manually deleted.
120
+ #
121
+ # Manually registered module names must conform to BCMS's module naming
122
+ # conventions, so this call will raise an InvalidModuleName exception:
123
+ # Cms::Settings.register("foo") => InvalidModuleName
124
+ #
125
+ # Module names must also be unique:
126
+ # Cms::Settings.modules => ["bcms_s3", "bcms_seo_sitemap"]
127
+ # Cms::Settings.register("bcms_s3") => ModuleConfigurationExists
128
+
129
+ def register(module_name)
130
+ register_modules [module_name], false
131
+ end
132
+
133
+ # Destroys the CmsModule object.
134
+ # Trying to delete a module that has not been registered raises an
135
+ # exception:
136
+ #
137
+ # Cms::Settings.modules => ["bcms_s3", "bcms_seo_sitemap"]
138
+ # Cms::Settings.delete("bcms_news") => ModuleNotRegistered
139
+ #
140
+ # At the moment it is possible to delete cms managed modules
141
+ # although they will be automatically registered again if
142
+ # Cms::Settings.synchronize is called.
143
+
144
+ def delete(module_name)
145
+ remove_modules [module_name.to_s]
146
+ end
147
+
148
+ # This method_missing implementation enables client code to call
149
+ # arbitrary methods on the Settings module. Undefined methods
150
+ # whose name does not conform to BCMS's module naming convention
151
+ # are handled elsewhere (presumably rasing a NoMethodError exception)
152
+ #
153
+ # If a module with name equal to the called method has been registered
154
+ # previously, a module method with the same name is defined (so it does not
155
+ # go through method missing again) and a proxy object is returned.
156
+ #
157
+ # If the module has not been registered previously, a ModuleNotRegistered
158
+ # exception is raised.
159
+ #
160
+ # Given:
161
+ # Cms::Settings.modules => ["bcms_s3", "bcms_seo_sitemap"]
162
+ #
163
+ # Cms::Settings.bcms_s3 => #<Cms::Settings: bcms_s3 => {"account_id"=>"NEW_ID"}
164
+ # Cms::Settings.bcms_news => ModuleNotRegistered
165
+ # Cms::Settings.foo => NoMethodError
166
+
167
+ def method_missing(method_id, *args)
168
+ method_name = method_id.to_s
169
+ unless method_name =~ CmsModule::NAME_REGEX
170
+ super(method_id, *args)
171
+ end
172
+ define_method(method_name) do
173
+ CmsModuleProxy.new(find_module(method_name))
174
+ end
175
+ send(method_name)
176
+ end
177
+
178
+ private
179
+ def registered_modules
180
+ CmsModule.all(:select => 'name').map { |m| m.name }
181
+ end
182
+
183
+ def managed_modules
184
+ CmsModule.managed.map {|m| m.name}
185
+ end
186
+
187
+ def installed_modules
188
+ Rails.configuration.gems.map do |g|
189
+ g.name if g.name =~ /^bcms_/
190
+ end.compact.uniq
191
+ end
192
+
193
+ def remove_modules(module_names)
194
+ module_names.each do |name|
195
+ verify_module_name(name)
196
+ find_module(name).destroy
197
+ end
198
+ end
199
+
200
+ def register_modules(module_names, managed = true)
201
+ module_names.each do |name|
202
+ verify_module_name(name)
203
+ begin
204
+ CmsModule.create!(:name => name.to_s,
205
+ :settings => {},
206
+ :cms_managed => managed)
207
+
208
+ rescue ActiveRecord::RecordInvalid
209
+ raise ModuleConfigurationExists,
210
+ "The module #{name} is already registered."
211
+ end
212
+ end
213
+ end
214
+
215
+ def verify_module_name(module_name)
216
+ unless module_name.to_s =~ CmsModule::NAME_REGEX
217
+ raise InvalidModuleName,
218
+ "#{module_name} is not a valid BrowserCMS module name. " +
219
+ "No modules were registered or deleted."
220
+ end
221
+ end
222
+
223
+ def find_module(module_name)
224
+ CmsModule.find_by_name!(module_name)
225
+ rescue ActiveRecord::RecordNotFound
226
+ raise ModuleNotRegistered,
227
+ "The module '#{module_name}' is not registered. " +
228
+ "Call Cms::Settings.register(#{module_name})."
229
+ end
230
+
231
+ # Calls to Cms::Settings.bcms_yxz, where bcms_yxz is a previously
232
+ # registered cms module, do not return ActiveRecord objects. Instead,
233
+ # the CmsModule object is wrapped in an instance of the CmsModuleProxy
234
+ # class, which provides acces to the underlying serialized hash through
235
+ # arbitrary method names.
236
+ class CmsModuleProxy < BlankSlate
237
+ def initialize(cms_module)
238
+ @cms_module = cms_module
239
+ end
240
+
241
+ def delete(key)
242
+ @cms_module.settings.delete(key)
243
+ @cms_module.save
244
+ end
245
+
246
+ def inspect
247
+ "#<Cms::Settings: #{@cms_module.name} => #{@cms_module.settings.inspect}>"
248
+ end
249
+
250
+ def method_missing(method_id, *args)
251
+ num_args = args.length
252
+ method_name = method_id.to_s
253
+ if method_name.chomp!("=")
254
+ @cms_module.settings[method_name] = args.first
255
+ @cms_module.save
256
+ elsif num_args == 0
257
+ @cms_module.settings[method_name]
258
+ else
259
+ super(method_id, *args)
260
+ end
261
+ end
262
+ end
263
+ end
264
+ end
265
+
@@ -0,0 +1,7 @@
1
+ module Cms::Routes
2
+ def routes_for_bcms_settings
3
+ namespace(:cms) do |cms|
4
+ #cms.content_blocks :settings
5
+ end
6
+ end
7
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,5 @@
1
+ gem_root = File.expand_path(File.join(File.dirname(__FILE__), ".."))
2
+ Cms.add_to_rails_paths gem_root
3
+ Cms.add_generator_paths gem_root, "db/migrate/[0-9]*_*.rb"
4
+
5
+ Cms::Settings.synchronize if CmsModule.table_exists?
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+ require 'performance_test_help'
3
+
4
+ # Profiling results for each test method are written to tmp/performance.
5
+ class BrowsingTest < ActionController::PerformanceTest
6
+ def test_homepage
7
+ get '/'
8
+ end
9
+ end
@@ -0,0 +1,38 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
3
+ require 'test_help'
4
+
5
+ class ActiveSupport::TestCase
6
+ # Transactional fixtures accelerate your tests by wrapping each test method
7
+ # in a transaction that's rolled back on completion. This ensures that the
8
+ # test database remains unchanged so your fixtures don't have to be reloaded
9
+ # between every test method. Fewer database queries means faster tests.
10
+ #
11
+ # Read Mike Clark's excellent walkthrough at
12
+ # http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
13
+ #
14
+ # Every Active Record database supports transactions except MyISAM tables
15
+ # in MySQL. Turn off transactional fixtures in this case; however, if you
16
+ # don't care one way or the other, switching from MyISAM to InnoDB tables
17
+ # is recommended.
18
+ #
19
+ # The only drawback to using transactional fixtures is when you actually
20
+ # need to test transactions. Since your test is bracketed by a transaction,
21
+ # any transactions started in your code will be automatically rolled back.
22
+ self.use_transactional_fixtures = true
23
+
24
+ # Instantiated fixtures are slow, but give you @david where otherwise you
25
+ # would need people(:david). If you don't want to migrate your existing
26
+ # test cases which use the @david style and don't mind the speed hit (each
27
+ # instantiated fixtures translates to a database query per test method),
28
+ # then set this back to true.
29
+ self.use_instantiated_fixtures = false
30
+
31
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
32
+ #
33
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
34
+ # -- they do not yet inherit this setting
35
+ fixtures :all
36
+
37
+ # Add more helper methods to be used by all tests here...
38
+ end
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+
3
+ class CmsModuleTest < ActiveSupport::TestCase
4
+
5
+ def valid_attributes
6
+ {
7
+ :name => 'bcms_blog',
8
+ :settings => {}
9
+ }
10
+ end
11
+
12
+ def setup
13
+ @blog_module = CmsModule.new(valid_attributes)
14
+ end
15
+
16
+ test "should be valid with valid attributes" do
17
+ assert @blog_module.valid?
18
+ end
19
+
20
+ test "should not be valid without a cms_name" do
21
+ @blog_module.name = ""
22
+ assert !@blog_module.valid?
23
+ end
24
+
25
+ test "should not be valid if cms_name is not a valid BCMS module name" do
26
+ @blog_module.name = "bcms s3"
27
+ assert !@blog_module.valid?
28
+ @blog_module.name = "BCMS_S3"
29
+ assert !@blog_module.valid?
30
+ @blog_module.name = "s3"
31
+ assert !@blog_module.valid?
32
+ @blog_module.name = "bcms-s3"
33
+ assert !@blog_module.valid?
34
+ @blog_module.name = "bcms_s3"
35
+ assert @blog_module.valid?
36
+ end
37
+
38
+ test "should not be valid if cms_name is not unique" do
39
+ @blog_module.save
40
+ assert !CmsModule.new(valid_attributes).valid?
41
+ end
42
+
43
+ end
44
+
@@ -0,0 +1,104 @@
1
+ require 'test_helper'
2
+ require 'mocha'
3
+
4
+ class SettingsTest < ActiveSupport::TestCase
5
+
6
+ def setup
7
+ @modules = %w[bcms_blog bcms_s3 bcms_seo_sitemap]
8
+ end
9
+
10
+ test "modules returns an array of registered module names"do
11
+ register_modules *@modules
12
+ assert_equal @modules, Cms::Settings.modules
13
+ end
14
+
15
+ test "synchronize registers modules from loadaed gems" do
16
+ Cms::Settings.expects(:installed_modules).returns(@modules).twice
17
+ Cms::Settings.synchronize
18
+ assert_equal @modules, Cms::Settings.modules
19
+ end
20
+
21
+ test "synchronize deletes modules not loaded as gems" do
22
+ register_modules *@modules
23
+ installed_modules = %w[bcms_blog bcms_s3]
24
+ Cms::Settings.expects(:installed_modules).returns(installed_modules).twice
25
+ Cms::Settings.synchronize
26
+ assert_equal installed_modules, Cms::Settings.modules
27
+ end
28
+
29
+ test "register registers a module and flags it as non managed" do
30
+ Cms::Settings.register('bcms_blog')
31
+ assert_equal ['bcms_blog'], Cms::Settings.modules
32
+ assert !CmsModule.first.cms_managed?
33
+ end
34
+
35
+ test "register raises InvalidModuleName if name does not conform to BCMS's module naming convention" do
36
+ assert_raise(Cms::Settings::InvalidModuleName) do
37
+ Cms::Settings.register("invalid name")
38
+ end
39
+ end
40
+
41
+ test "register raises ModuleConfigurationExists if the module is already registered" do
42
+ register_modules *@modules
43
+ assert_raise(Cms::Settings::ModuleConfigurationExists) do
44
+ Cms::Settings.register('bcms_blog')
45
+ end
46
+ end
47
+
48
+ test "synchronize does not delete modules flagged as not managed" do
49
+ Cms::Settings.register('bcms_blog')
50
+ Cms::Settings.synchronize
51
+ assert_equal ['bcms_blog'], Cms::Settings.modules
52
+ end
53
+
54
+ test "delete destroys the module" do
55
+ Cms::Settings.register('bcms_blog')
56
+ assert_equal ['bcms_blog'], Cms::Settings.modules
57
+ Cms::Settings.delete('bcms_blog')
58
+ assert_equal [], Cms::Settings.modules
59
+ end
60
+
61
+ test "trying to delete a module that has not been registered raises ModuleNotRegistered" do
62
+ assert_raise(Cms::Settings::ModuleNotRegistered) do
63
+ Cms::Settings.delete('bcms_blog')
64
+ end
65
+ end
66
+
67
+ test "defines methods for accessing user registered modules" do
68
+ Cms::Settings.register('bcms_blog')
69
+ assert !Cms::Settings.respond_to?(:bcms_blog)
70
+ Cms::Settings.bcms_blog
71
+ assert Cms::Settings.respond_to?(:bcms_blog)
72
+ end
73
+
74
+ test "defines methods for cms managed modules" do
75
+ Cms::Settings.expects(:installed_modules).returns(@modules).twice
76
+ Cms::Settings.synchronize
77
+ assert !Cms::Settings.respond_to?(:bcms_s3)
78
+ Cms::Settings.bcms_s3
79
+ assert Cms::Settings.respond_to?(:bcms_s3)
80
+ assert !Cms::Settings.respond_to?(:bcms_seo_sitemap)
81
+ Cms::Settings.bcms_seo_sitemap
82
+ assert Cms::Settings.respond_to?(:bcms_seo_sitemap)
83
+ end
84
+
85
+ test "raises ModuleNotRegistered if a method with name of not installed module is called" do
86
+ assert_raise(Cms::Settings::ModuleNotRegistered) do
87
+ Cms::Settings.bcms_not_registered
88
+ end
89
+ end
90
+
91
+ test "raises NoMethodError for undefined methods that do not conform with BCMS module naming convention " do
92
+ assert_raise(NoMethodError) do
93
+ Cms::Settings.wibble
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def register_modules(*names)
100
+ names.each {|n| CmsModule.create(:name => n, :settings => {})}
101
+ end
102
+
103
+ end
104
+
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bcms_settings
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - BrowserMedia
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-29 00:00:00 -06:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: browsercms
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 1
33
+ - 2
34
+ version: 3.1.2
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: This module provides a global persisted key value store that can be used to keep configuration key value pairs
38
+ email: github@browsermedia.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - LICENSE.txt
45
+ - README
46
+ files:
47
+ - app/controllers/application_controller.rb
48
+ - app/helpers/application_helper.rb
49
+ - app/models/cms_module.rb
50
+ - db/migrate/20101129011429_create_cms_modules.rb
51
+ - doc/README_FOR_APP
52
+ - lib/bcms_settings.rb
53
+ - lib/bcms_settings/cms/settings.rb
54
+ - lib/bcms_settings/routes.rb
55
+ - rails/init.rb
56
+ - LICENSE.txt
57
+ - README
58
+ - test/performance/browsing_test.rb
59
+ - test/test_helper.rb
60
+ - test/unit/cms_module_test.rb
61
+ - test/unit/lib/cms/settings_test.rb
62
+ has_rdoc: true
63
+ homepage: http://browsercms.org
64
+ licenses: []
65
+
66
+ post_install_message:
67
+ rdoc_options:
68
+ - --charset=UTF-8
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project: browsercms
92
+ rubygems_version: 1.3.7
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Global settings storage for BrowserCMS
96
+ test_files:
97
+ - test/performance/browsing_test.rb
98
+ - test/test_helper.rb
99
+ - test/unit/cms_module_test.rb
100
+ - test/unit/lib/cms/settings_test.rb