grippy-doozer 0.1.0
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/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +57 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/bin/doozer +8 -0
- data/doozer.gemspec +114 -0
- data/lib/doozer/README.rb +40 -0
- data/lib/doozer/active_support/array.rb +14 -0
- data/lib/doozer/active_support/class.rb +221 -0
- data/lib/doozer/active_support/date_time.rb +23 -0
- data/lib/doozer/active_support/object.rb +43 -0
- data/lib/doozer/active_support/time.rb +32 -0
- data/lib/doozer/app.rb +265 -0
- data/lib/doozer/configs.rb +131 -0
- data/lib/doozer/controller.rb +335 -0
- data/lib/doozer/extend.rb +10 -0
- data/lib/doozer/initializer.rb +95 -0
- data/lib/doozer/lib.rb +32 -0
- data/lib/doozer/logger.rb +11 -0
- data/lib/doozer/orm/active_record.rb +19 -0
- data/lib/doozer/orm/data_mapper.rb +19 -0
- data/lib/doozer/orm/sequel.rb +18 -0
- data/lib/doozer/partial.rb +99 -0
- data/lib/doozer/plugins/paginate/init.rb +2 -0
- data/lib/doozer/plugins/paginate/lib/paginate/collection.rb +60 -0
- data/lib/doozer/plugins/paginate/lib/paginate/finder.rb +116 -0
- data/lib/doozer/plugins/paginate/lib/paginate/view_helpers.rb +37 -0
- data/lib/doozer/plugins/paginate/lib/paginate.rb +32 -0
- data/lib/doozer/rackup/server.ru +37 -0
- data/lib/doozer/rackup/test.rb +19 -0
- data/lib/doozer/redirect.rb +12 -0
- data/lib/doozer/route.rb +264 -0
- data/lib/doozer/scripts/cluster.rb +132 -0
- data/lib/doozer/scripts/migrate.rb +108 -0
- data/lib/doozer/scripts/task.rb +60 -0
- data/lib/doozer/scripts/test.rb +23 -0
- data/lib/doozer/version.rb +8 -0
- data/lib/doozer/view_helpers.rb +163 -0
- data/lib/doozer/watcher.rb +375 -0
- data/lib/doozer.rb +30 -0
- data/lib/generator/generator.rb +547 -0
- data/templates/skeleton/Rakefile +3 -0
- data/templates/skeleton/app/controllers/application_controller.rb +2 -0
- data/templates/skeleton/app/controllers/index_controller.rb +7 -0
- data/templates/skeleton/app/helpers/application_helper.rb +17 -0
- data/templates/skeleton/app/views/global/_header.html.erb +7 -0
- data/templates/skeleton/app/views/global/_navigation.html.erb +6 -0
- data/templates/skeleton/app/views/index/index.html.erb +108 -0
- data/templates/skeleton/app/views/layouts/default.html.erb +23 -0
- data/templates/skeleton/config/app.yml +31 -0
- data/templates/skeleton/config/database.yml +25 -0
- data/templates/skeleton/config/environment.rb +13 -0
- data/templates/skeleton/config/rack.rb +30 -0
- data/templates/skeleton/config/routes.rb +69 -0
- data/templates/skeleton/script/cluster +5 -0
- data/templates/skeleton/script/migrate +5 -0
- data/templates/skeleton/script/task +5 -0
- data/templates/skeleton/script/test +4 -0
- data/templates/skeleton/static/404.html +16 -0
- data/templates/skeleton/static/500.html +16 -0
- data/templates/skeleton/static/css/style.css +32 -0
- data/templates/skeleton/static/favicon.ico +0 -0
- data/templates/skeleton/static/js/application.js +1 -0
- data/templates/skeleton/static/js/jquery-1.3.min.js +19 -0
- data/templates/skeleton/static/robots.txt +5 -0
- data/templates/skeleton/test/fixtures/setup.rb +6 -0
- data/templates/skeleton/test/setup.rb +33 -0
- data/test/doozer_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +126 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Greg Melton
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
= What is Doozer?
|
2
|
+
* A lightweight, ORM agnostic, Rack (http://rack.rubyforge.org) compatible MVC framework.
|
3
|
+
|
4
|
+
== Project Inspiration
|
5
|
+
* Doozer was initially a project I started working on for Google App Engine. It was eventually abandoned since GAE lacked (at the time and may still) proper support for migrations. I ported some of the code to Ruby mainly to learn the internals of Rack back in December 2008.
|
6
|
+
* Rails conventions and methodologies (mostly the application structure, configuration, nomenclature, scripts, and a few viewhelper methods).
|
7
|
+
* Clustering ala Mongrel::Cluster
|
8
|
+
|
9
|
+
== Requirements
|
10
|
+
* Ruby < 1.9 (untestested on Ruby 1.9 as of now)
|
11
|
+
* Rack (http://rack.rubyforge.org) gem (0.9.1 or 1.0.0)
|
12
|
+
* Any http server supported by Rack
|
13
|
+
* ActiveRecord, DataMapper or Sequel (only if you need DB support)
|
14
|
+
|
15
|
+
== Getting Started
|
16
|
+
1. Install the gem(s):
|
17
|
+
- gem sources -a http://gems.github.com (if you haven't already)
|
18
|
+
- sudo gem install rack
|
19
|
+
- sudo gem install grippy-doozer
|
20
|
+
2. Run 'doozer test-app' to generate the base application skeleton.
|
21
|
+
3. Fire up the application in development mode
|
22
|
+
- cd test-app
|
23
|
+
- script/cluster -C start
|
24
|
+
4. Navigate to http://localhost:9292
|
25
|
+
|
26
|
+
== Configuration
|
27
|
+
* Doozer is configurable to use an ORM library of your choosing: ActiveRecord, DataMapper, or Sequel.
|
28
|
+
* By default, routes are handled by Doozer controllers or you can define other Rack compatible applications which handle specific request paths.
|
29
|
+
* Http server of your liking (Mongrel, Thin, Lighttpd, or anything supported by Rack).
|
30
|
+
* Multiple appservers.
|
31
|
+
* Static directories.
|
32
|
+
|
33
|
+
== Useful Scripts
|
34
|
+
* Generate an application skeleton. Run 'doozer test-app' (see Getting Started).
|
35
|
+
* Generate views, controllers, and models (depending on the configured ORM). Run 'doozer generate -h' for more info.
|
36
|
+
* start/stop/restart your web server(s). Run 'script/cluster -h' for more info.
|
37
|
+
* Migrations up or down. 'script/migrate -h'.
|
38
|
+
* Tasks. Run 'script/task -h' for more info
|
39
|
+
* There is a rudimentary test command which allows you to run your own test suite for your application. Run 'script/test -h' for more info.
|
40
|
+
|
41
|
+
== Current limitations:
|
42
|
+
* Doozer has no test suite. Tsk-tsk I know. In the works.
|
43
|
+
* Right now, it doesn't keep track of migration versions.
|
44
|
+
* Magic routes are turned off. Still debating adding them back.
|
45
|
+
* Not all the documentation is in place.
|
46
|
+
|
47
|
+
== Note on Patches/Pull Requests
|
48
|
+
* Fork the project.
|
49
|
+
* Make your feature addition or bug fix.
|
50
|
+
* Add tests for it. This is important so I don't break it in a
|
51
|
+
future version unintentionally.
|
52
|
+
* Commit, do not mess with rakefile, version, or history.
|
53
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
54
|
+
* Send me a pull request. Bonus points for topic branches.
|
55
|
+
|
56
|
+
== Copyright
|
57
|
+
Copyright (c) 2009 Greg Melton. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "doozer"
|
8
|
+
gem.summary = %Q{A little MVC framework for Rack applications.}
|
9
|
+
gem.description = %Q{This GEM provides a small, barebones framework for creating MVC Rack applications.}
|
10
|
+
gem.email = "gmelton@whorde.com"
|
11
|
+
gem.homepage = "http://github.com/grippy/doozer"
|
12
|
+
gem.authors = ["grippy"]
|
13
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
14
|
+
gem.files.include %w() # lib/**/**/**/**/** templates/**/**/**/**
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/*_test.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/*_test.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
task :default => :test
|
46
|
+
|
47
|
+
require 'rake/rdoctask'
|
48
|
+
Rake::RDocTask.new do |rdoc|
|
49
|
+
if File.exist?('VERSION')
|
50
|
+
version = File.read('VERSION')
|
51
|
+
else
|
52
|
+
version = ""
|
53
|
+
end
|
54
|
+
|
55
|
+
rdoc.rdoc_dir = 'rdoc'
|
56
|
+
rdoc.title = "doozer #{version}"
|
57
|
+
rdoc.rdoc_files.include('README*')
|
58
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
59
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bin/doozer
ADDED
data/doozer.gemspec
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{doozer}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["grippy"]
|
12
|
+
s.date = %q{2009-08-09}
|
13
|
+
s.default_executable = %q{doozer}
|
14
|
+
s.description = %q{This GEM provides a small, barebones framework for creating MVC Rack applications.}
|
15
|
+
s.email = %q{gmelton@whorde.com}
|
16
|
+
s.executables = ["doozer"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.rdoc"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".gitignore",
|
24
|
+
"LICENSE",
|
25
|
+
"README.rdoc",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"bin/doozer",
|
29
|
+
"doozer.gemspec",
|
30
|
+
"lib/doozer.rb",
|
31
|
+
"lib/doozer/README.rb",
|
32
|
+
"lib/doozer/active_support/array.rb",
|
33
|
+
"lib/doozer/active_support/class.rb",
|
34
|
+
"lib/doozer/active_support/date_time.rb",
|
35
|
+
"lib/doozer/active_support/object.rb",
|
36
|
+
"lib/doozer/active_support/time.rb",
|
37
|
+
"lib/doozer/app.rb",
|
38
|
+
"lib/doozer/configs.rb",
|
39
|
+
"lib/doozer/controller.rb",
|
40
|
+
"lib/doozer/extend.rb",
|
41
|
+
"lib/doozer/initializer.rb",
|
42
|
+
"lib/doozer/lib.rb",
|
43
|
+
"lib/doozer/logger.rb",
|
44
|
+
"lib/doozer/orm/active_record.rb",
|
45
|
+
"lib/doozer/orm/data_mapper.rb",
|
46
|
+
"lib/doozer/orm/sequel.rb",
|
47
|
+
"lib/doozer/partial.rb",
|
48
|
+
"lib/doozer/plugins/paginate/init.rb",
|
49
|
+
"lib/doozer/plugins/paginate/lib/paginate.rb",
|
50
|
+
"lib/doozer/plugins/paginate/lib/paginate/collection.rb",
|
51
|
+
"lib/doozer/plugins/paginate/lib/paginate/finder.rb",
|
52
|
+
"lib/doozer/plugins/paginate/lib/paginate/view_helpers.rb",
|
53
|
+
"lib/doozer/rackup/server.ru",
|
54
|
+
"lib/doozer/rackup/test.rb",
|
55
|
+
"lib/doozer/redirect.rb",
|
56
|
+
"lib/doozer/route.rb",
|
57
|
+
"lib/doozer/scripts/cluster.rb",
|
58
|
+
"lib/doozer/scripts/migrate.rb",
|
59
|
+
"lib/doozer/scripts/task.rb",
|
60
|
+
"lib/doozer/scripts/test.rb",
|
61
|
+
"lib/doozer/version.rb",
|
62
|
+
"lib/doozer/view_helpers.rb",
|
63
|
+
"lib/doozer/watcher.rb",
|
64
|
+
"lib/generator/generator.rb",
|
65
|
+
"templates/skeleton/Rakefile",
|
66
|
+
"templates/skeleton/app/controllers/application_controller.rb",
|
67
|
+
"templates/skeleton/app/controllers/index_controller.rb",
|
68
|
+
"templates/skeleton/app/helpers/application_helper.rb",
|
69
|
+
"templates/skeleton/app/views/global/_header.html.erb",
|
70
|
+
"templates/skeleton/app/views/global/_navigation.html.erb",
|
71
|
+
"templates/skeleton/app/views/index/index.html.erb",
|
72
|
+
"templates/skeleton/app/views/layouts/default.html.erb",
|
73
|
+
"templates/skeleton/config/app.yml",
|
74
|
+
"templates/skeleton/config/database.yml",
|
75
|
+
"templates/skeleton/config/environment.rb",
|
76
|
+
"templates/skeleton/config/rack.rb",
|
77
|
+
"templates/skeleton/config/routes.rb",
|
78
|
+
"templates/skeleton/script/cluster",
|
79
|
+
"templates/skeleton/script/migrate",
|
80
|
+
"templates/skeleton/script/task",
|
81
|
+
"templates/skeleton/script/test",
|
82
|
+
"templates/skeleton/static/404.html",
|
83
|
+
"templates/skeleton/static/500.html",
|
84
|
+
"templates/skeleton/static/css/style.css",
|
85
|
+
"templates/skeleton/static/favicon.ico",
|
86
|
+
"templates/skeleton/static/js/application.js",
|
87
|
+
"templates/skeleton/static/js/jquery-1.3.min.js",
|
88
|
+
"templates/skeleton/static/robots.txt",
|
89
|
+
"templates/skeleton/test/fixtures/setup.rb",
|
90
|
+
"templates/skeleton/test/setup.rb",
|
91
|
+
"test/doozer_test.rb",
|
92
|
+
"test/test_helper.rb"
|
93
|
+
]
|
94
|
+
s.has_rdoc = true
|
95
|
+
s.homepage = %q{http://github.com/grippy/doozer}
|
96
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
97
|
+
s.require_paths = ["lib"]
|
98
|
+
s.rubygems_version = %q{1.3.1}
|
99
|
+
s.summary = %q{A little MVC framework for Rack applications.}
|
100
|
+
s.test_files = [
|
101
|
+
"test/doozer_test.rb",
|
102
|
+
"test/test_helper.rb"
|
103
|
+
]
|
104
|
+
|
105
|
+
if s.respond_to? :specification_version then
|
106
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
107
|
+
s.specification_version = 2
|
108
|
+
|
109
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
110
|
+
else
|
111
|
+
end
|
112
|
+
else
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# = What is Doozer?
|
2
|
+
# * A lightweight, ORM agnostic, Rack (http://rack.rubyforge.org) compatible MVC framework.
|
3
|
+
#
|
4
|
+
# == Project Inspiration
|
5
|
+
# * Doozer was initially a project I started working on for Google App Engine. It was eventually abandoned since GAE lacked (at the time and may still) proper support for migrations. I ported some of the code to Ruby mainly to learn the internals of Rack back in December 2008.
|
6
|
+
# * Some of the more useful Rails conventions and methodologies (mostly the application structure, configuration, nonmenclature, scripts, and a few viewhelper methods).
|
7
|
+
# * Clustering ala Mongrel::Cluster
|
8
|
+
#
|
9
|
+
# == Requirements
|
10
|
+
# * Ruby < 1.9 (untestested on Ruby 1.9 as of now)
|
11
|
+
# * Rack (http://rack.rubyforge.org) gem (0.9.1 or 1.0.0)
|
12
|
+
# * An http server supported by Rack
|
13
|
+
# * ActiveRecord, DataMapper or Sequel
|
14
|
+
#
|
15
|
+
# == Getting Started
|
16
|
+
# 1. Create a folder called 'test' and checkout Doozer.
|
17
|
+
# 2. From the root 'test' directory run 'ruby doozer/commands/scaffold.rb' to generate the base application skeleton.
|
18
|
+
# 3. Fire up the application in development mode=> 'script/clusters -C start'.
|
19
|
+
# 4. Navigate to http://localhost:9292
|
20
|
+
#
|
21
|
+
# == Configuration
|
22
|
+
# * Doozer is configurable to use an ORM library of your choosing: ActiveRecord, DataMapper, or Sequel.
|
23
|
+
# * By default, routes are handled by Doozer controllers or you can define other Rack compatible applications which handle specific request paths.
|
24
|
+
# * Http server of your liking (Mongrel, Thin, Lighttpd, or anything supported by Rack).
|
25
|
+
# * Multiple appservers.
|
26
|
+
# * Static directories.
|
27
|
+
#
|
28
|
+
# == Useful Scripts
|
29
|
+
# * Generate an application skeleton. Run 'ruby doozer/commands/scaffold.rb' (see Getting Started).
|
30
|
+
# * Generate views, controllers, and models (depending on the configured ORM). Run 'script/generate -h' for more info.
|
31
|
+
# * start/stop/restart your web server(s). Run 'script/clusters -h' for more info.
|
32
|
+
# * Migrations up or down. 'script/migrate -h'.
|
33
|
+
# * Tasks. Run 'script/task -h' for more info
|
34
|
+
# * There is a rudimentary test command which allows you to run your own test suite for your application. Run 'script/test -h' for more info.
|
35
|
+
#
|
36
|
+
# == Current limitations:
|
37
|
+
# * Doozer has no test suite. Tsk-tsk I know. In the works.
|
38
|
+
# * Right now, it doesn't keep track of migration versions.
|
39
|
+
# * Magic routes are turned off. These worked at one point. They may work again one day.
|
40
|
+
# * No way to override a view template from inside an action.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Array
|
2
|
+
# Extracts options from a set of arguments. Removes and returns the last
|
3
|
+
# element in the array if it's a hash, otherwise returns a blank hash.
|
4
|
+
#
|
5
|
+
# def options(*args)
|
6
|
+
# args.extract_options!
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
# options(1, 2) # => {}
|
10
|
+
# options(1, 2, :a => :b) # => {:a=>:b}
|
11
|
+
def extract_options!
|
12
|
+
last.is_a?(::Hash) ? pop : {}
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
# Retain for backward compatibility. Methods are now included in Class.
|
2
|
+
module ClassInheritableAttributes # :nodoc:
|
3
|
+
end
|
4
|
+
|
5
|
+
# Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
|
6
|
+
# their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
|
7
|
+
# to, for example, an array without those additions being shared with either their parent, siblings, or
|
8
|
+
# children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
|
9
|
+
class Class # :nodoc:
|
10
|
+
def class_inheritable_reader(*syms)
|
11
|
+
syms.each do |sym|
|
12
|
+
next if sym.is_a?(Hash)
|
13
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
14
|
+
def self.#{sym} # def self.after_add
|
15
|
+
read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:after_add)
|
16
|
+
end # end
|
17
|
+
|
18
|
+
def #{sym} # def after_add
|
19
|
+
self.class.#{sym} # self.class.after_add
|
20
|
+
end # end
|
21
|
+
EOS
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def class_inheritable_writer(*syms)
|
26
|
+
options = syms.extract_options!
|
27
|
+
syms.each do |sym|
|
28
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
29
|
+
def self.#{sym}=(obj) # def self.color=(obj)
|
30
|
+
write_inheritable_attribute(:#{sym}, obj) # write_inheritable_attribute(:color, obj)
|
31
|
+
end # end
|
32
|
+
#
|
33
|
+
#{" #
|
34
|
+
def #{sym}=(obj) # def color=(obj)
|
35
|
+
self.class.#{sym} = obj # self.class.color = obj
|
36
|
+
end # end
|
37
|
+
" unless options[:instance_writer] == false } # # the writer above is generated unless options[:instance_writer] == false
|
38
|
+
EOS
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def class_inheritable_array_writer(*syms)
|
43
|
+
options = syms.extract_options!
|
44
|
+
syms.each do |sym|
|
45
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
46
|
+
def self.#{sym}=(obj) # def self.levels=(obj)
|
47
|
+
write_inheritable_array(:#{sym}, obj) # write_inheritable_array(:levels, obj)
|
48
|
+
end # end
|
49
|
+
#
|
50
|
+
#{" #
|
51
|
+
def #{sym}=(obj) # def levels=(obj)
|
52
|
+
self.class.#{sym} = obj # self.class.levels = obj
|
53
|
+
end # end
|
54
|
+
" unless options[:instance_writer] == false } # # the writer above is generated unless options[:instance_writer] == false
|
55
|
+
EOS
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def class_inheritable_hash_writer(*syms)
|
60
|
+
options = syms.extract_options!
|
61
|
+
syms.each do |sym|
|
62
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
63
|
+
def self.#{sym}=(obj) # def self.nicknames=(obj)
|
64
|
+
write_inheritable_hash(:#{sym}, obj) # write_inheritable_hash(:nicknames, obj)
|
65
|
+
end # end
|
66
|
+
#
|
67
|
+
#{" #
|
68
|
+
def #{sym}=(obj) # def nicknames=(obj)
|
69
|
+
self.class.#{sym} = obj # self.class.nicknames = obj
|
70
|
+
end # end
|
71
|
+
" unless options[:instance_writer] == false } # # the writer above is generated unless options[:instance_writer] == false
|
72
|
+
EOS
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def class_inheritable_accessor(*syms)
|
77
|
+
class_inheritable_reader(*syms)
|
78
|
+
class_inheritable_writer(*syms)
|
79
|
+
end
|
80
|
+
|
81
|
+
def class_inheritable_array(*syms)
|
82
|
+
class_inheritable_reader(*syms)
|
83
|
+
class_inheritable_array_writer(*syms)
|
84
|
+
end
|
85
|
+
|
86
|
+
def class_inheritable_hash(*syms)
|
87
|
+
class_inheritable_reader(*syms)
|
88
|
+
class_inheritable_hash_writer(*syms)
|
89
|
+
end
|
90
|
+
|
91
|
+
def inheritable_attributes
|
92
|
+
@inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
|
93
|
+
end
|
94
|
+
|
95
|
+
def write_inheritable_attribute(key, value)
|
96
|
+
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
97
|
+
@inheritable_attributes = {}
|
98
|
+
end
|
99
|
+
inheritable_attributes[key] = value
|
100
|
+
end
|
101
|
+
|
102
|
+
def write_inheritable_array(key, elements)
|
103
|
+
write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
|
104
|
+
write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
|
105
|
+
end
|
106
|
+
|
107
|
+
def write_inheritable_hash(key, hash)
|
108
|
+
write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
|
109
|
+
write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
|
110
|
+
end
|
111
|
+
|
112
|
+
def read_inheritable_attribute(key)
|
113
|
+
inheritable_attributes[key]
|
114
|
+
end
|
115
|
+
|
116
|
+
def reset_inheritable_attributes
|
117
|
+
@inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
# Prevent this constant from being created multiple times
|
122
|
+
EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
|
123
|
+
|
124
|
+
def inherited_with_inheritable_attributes(child)
|
125
|
+
inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
|
126
|
+
|
127
|
+
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
128
|
+
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
129
|
+
else
|
130
|
+
new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
|
131
|
+
memo.update(key => value.duplicable? ? value.dup : value)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
|
136
|
+
end
|
137
|
+
|
138
|
+
alias inherited_without_inheritable_attributes inherited
|
139
|
+
alias inherited inherited_with_inheritable_attributes
|
140
|
+
end
|
141
|
+
|
142
|
+
class Class
|
143
|
+
# Defines class-level inheritable attribute reader. Attributes are available to subclasses,
|
144
|
+
# each subclass has a copy of parent's attribute.
|
145
|
+
#
|
146
|
+
# @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
|
147
|
+
# @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
|
148
|
+
#
|
149
|
+
# @api public
|
150
|
+
#
|
151
|
+
# @todo Do we want to block instance_reader via :instance_reader => false
|
152
|
+
# @todo It would be preferable that we do something with a Hash passed in
|
153
|
+
# (error out or do the same as other methods above) instead of silently
|
154
|
+
# moving on). In particular, this makes the return value of this function
|
155
|
+
# less useful.
|
156
|
+
def extlib_inheritable_reader(*ivars)
|
157
|
+
instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
|
158
|
+
|
159
|
+
ivars.each do |ivar|
|
160
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
161
|
+
def self.#{ivar}
|
162
|
+
return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
|
163
|
+
ivar = superclass.#{ivar}
|
164
|
+
return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
|
165
|
+
@#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar
|
166
|
+
end
|
167
|
+
RUBY
|
168
|
+
unless instance_reader == false
|
169
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
170
|
+
def #{ivar}
|
171
|
+
self.class.#{ivar}
|
172
|
+
end
|
173
|
+
RUBY
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Defines class-level inheritable attribute writer. Attributes are available to subclasses,
|
179
|
+
# each subclass has a copy of parent's attribute.
|
180
|
+
#
|
181
|
+
# @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
|
182
|
+
# define inheritable writer for.
|
183
|
+
# @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
|
184
|
+
# @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
|
185
|
+
#
|
186
|
+
# @api public
|
187
|
+
#
|
188
|
+
# @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
|
189
|
+
# class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
|
190
|
+
def extlib_inheritable_writer(*ivars)
|
191
|
+
instance_writer = ivars.pop[:writer] if ivars.last.is_a?(Hash)
|
192
|
+
ivars.each do |ivar|
|
193
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
194
|
+
def self.#{ivar}=(obj)
|
195
|
+
@#{ivar} = obj
|
196
|
+
end
|
197
|
+
RUBY
|
198
|
+
unless instance_writer == false
|
199
|
+
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
200
|
+
def #{ivar}=(obj) self.class.#{ivar} = obj end
|
201
|
+
RUBY
|
202
|
+
end
|
203
|
+
|
204
|
+
self.send("#{ivar}=", yield) if block_given?
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
|
209
|
+
# each subclass has a copy of parent's attribute.
|
210
|
+
#
|
211
|
+
# @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
|
212
|
+
# define inheritable accessor for.
|
213
|
+
# @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
|
214
|
+
# @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
|
215
|
+
#
|
216
|
+
# @api public
|
217
|
+
def extlib_inheritable_accessor(*syms, &block)
|
218
|
+
extlib_inheritable_reader(*syms)
|
219
|
+
extlib_inheritable_writer(*syms, &block)
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Default DATE_FORMATS available
|
2
|
+
#
|
3
|
+
# Time::DATE_FORMATS.merge!({
|
4
|
+
# :db => "%Y-%m-%d %H:%M:%S",
|
5
|
+
# :number => "%Y%m%d%H%M%S",
|
6
|
+
# :time => "%H:%M",
|
7
|
+
# :mdy => "%B %d, %Y",
|
8
|
+
# :short => "%d %b %H:%M",
|
9
|
+
# :long => "%B %d, %Y %H:%M"
|
10
|
+
# })
|
11
|
+
# === Example Useage
|
12
|
+
# DateTime.now().to_format(:mdy)
|
13
|
+
#
|
14
|
+
class DateTime
|
15
|
+
# Helper method for string formatting DateTime.
|
16
|
+
def to_format(key = :default)
|
17
|
+
if format = ::Time::DATE_FORMATS[key]
|
18
|
+
strftime(format)
|
19
|
+
else
|
20
|
+
to_s
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Object
|
2
|
+
# Can you safely .dup this object?
|
3
|
+
# False for nil, false, true, symbols, numbers, and class objects; true otherwise.
|
4
|
+
def duplicable?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class NilClass #:nodoc:
|
10
|
+
def duplicable?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class FalseClass #:nodoc:
|
16
|
+
def duplicable?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class TrueClass #:nodoc:
|
22
|
+
def duplicable?
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Symbol #:nodoc:
|
28
|
+
def duplicable?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Numeric #:nodoc:
|
34
|
+
def duplicable?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Class #:nodoc:
|
40
|
+
def duplicable?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Default DATE_FORMATS available
|
2
|
+
#
|
3
|
+
# Time::DATE_FORMATS.merge!({
|
4
|
+
# :db => "%Y-%m-%d %H:%M:%S",
|
5
|
+
# :number => "%Y%m%d%H%M%S",
|
6
|
+
# :time => "%H:%M",
|
7
|
+
# :mdy => "%B %d, %Y",
|
8
|
+
# :short => "%d %b %H:%M",
|
9
|
+
# :long => "%B %d, %Y %H:%M"
|
10
|
+
# })
|
11
|
+
# === Example Useage
|
12
|
+
# DateTime.now().to_format(:mdy)
|
13
|
+
#
|
14
|
+
class Time
|
15
|
+
# Helper method for string formatting Time.
|
16
|
+
DATE_FORMATS = {
|
17
|
+
:db => "%Y-%m-%d %H:%M:%S",
|
18
|
+
:number => "%Y%m%d%H%M%S",
|
19
|
+
:time => "%H:%M",
|
20
|
+
:mdy => "%B %d, %Y",
|
21
|
+
:short => "%d %b %H:%M",
|
22
|
+
:long => "%B %d, %Y %H:%M"
|
23
|
+
}
|
24
|
+
|
25
|
+
def to_format(key = :default)
|
26
|
+
if format = ::Time::DATE_FORMATS[key]
|
27
|
+
strftime(format)
|
28
|
+
else
|
29
|
+
to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|