app 0.2.2 → 0.9.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.
@@ -1,3 +1,10 @@
1
+ === 0.9.0 / 2010-02-21
2
+
3
+ * 1 major enhancement
4
+
5
+ * Rebirthday!
6
+
7
+
1
8
  === 0.2.2 / 2009-04-17
2
9
 
3
10
  * 2 minor enhancements
@@ -25,6 +32,7 @@
25
32
  * Removed superfluous "init" and "uninstall" files (handle load errors more
26
33
  gracefully in "app", and let "script/destroy" do its thing).
27
34
 
35
+
28
36
  === 0.1.2 / 2009-04-02
29
37
 
30
38
  * 1 minor enhancement
@@ -1,127 +1,129 @@
1
1
  = App
2
2
 
3
- http://github.com/stephencelis/app
4
-
5
-
6
- == DESCRIPTION
7
-
8
3
  Move the config out of your app, and into App.
9
4
 
10
- Sure, it's been done before, and others will do it again, but this is my way,
11
- and I like it.
12
-
13
-
14
- == FEATURES/PROBLEMS
15
-
16
- * Easy, environmentally-friendly configuration access.
17
-
18
-
19
- For mutability, try acts_as_singleton or KVC:
20
-
21
- * http://github.com/stephencelis/acts_as_singleton
22
- * http://github.com/stephencelis/kvc
23
-
24
-
25
- == SYNOPSIS
26
-
27
- App looks for and loads configuration from "config/app.yml", providing a
28
- namespaced API for access.
29
-
30
- App.config # => {"apis"=>{"flickr"=>{ ... }}
31
-
32
-
33
- Sugar is always sweeter:
34
-
35
- App.config("apis", "flickr") # => App.config["apis"]["flickr"]
36
-
37
-
38
- Who doesn't like sugar?
39
5
 
40
- App["apis", "flickr"]
6
+ == WARNING:
41
7
 
8
+ This release is new, improved, and almost completely incompatible with the
9
+ gem formerly known as App. (See "What about YAML?", below.)
42
10
 
43
- Sugar, sugar, sugar.
44
11
 
45
- App.apis("flickr")
12
+ == K.
46
13
 
14
+ === Rails (3.0)
47
15
 
48
- Let's not overdo it, though. <tt>App.apis.flickr</tt> just doesn't look right.
16
+ % echo 'gem "app"' >> Gemfile
17
+ % bundle install
18
+ % rails g configurable
49
19
 
50
20
 
51
- == REQUIREMENTS
21
+ You now have App config files at config/app. It will generate an override per
22
+ Rails environment.
52
23
 
53
- * Rails 2.3.2 or greater.
24
+ # config/app.rb
25
+ class App < Configurable
26
+ config.javascript_expansions = {
27
+ :prototype => "prototype"
28
+ :scriptaculous => %w(effects dragdrop controls)
29
+ }
30
+ end
54
31
 
55
32
 
56
- == INSTALL
33
+ Need to update those sources for production?
57
34
 
58
- === With a template:
35
+ # config/app/production.rb
36
+ App.configure do
37
+ ajax_lib_base = "http://ajax.googleapis.com/ajax/libs"
59
38
 
60
- In existing projects:
39
+ config.javascript_expansions.update({
40
+ :prototype => "#{ajax_lib_base}/prototype/1.6.1.0/prototype.js"
41
+ :scriptaculous => "#{ajax_lib_base}/scriptaculous/1.8.3/scriptaculous.js"
42
+ })
43
+ end
61
44
 
62
- % rake rails:template LOCATION=http://gist.github.com/97629.txt
63
45
 
46
+ === Ruby
64
47
 
65
- For new projects:
48
+ App can be used in any Ruby application. Just bundle (see "Rails", above, less
49
+ the `rails g`) or install the gem.
66
50
 
67
- % rails newapp -m http://gist.github.com/97629.txt
51
+ Make sure "app" is required in your environment, and define a class from there.
68
52
 
53
+ class MyConfig < Configurable
54
+ config.launched_at = Time.now.utc
55
+ end
69
56
 
70
- === Or as a gem:
71
57
 
72
- Configure:
58
+ == What about YAML?
73
59
 
74
- # config/environment.rb
75
- config.gem "stephencelis-app", :lib => "app",
76
- :source => "http://gems.github.com",
77
- :version => ">= 0.2.2"
60
+ YAML is great, really, but it just wasn't great beyond simple configuration.
78
61
 
79
- And install:
62
+ Take that last example. ERB would be required, and still it's cumbersome.
80
63
 
81
- % sudo rake gems:install
64
+ # app.yml
65
+ ---
66
+ launched_at: <%= Time.now.utc.iso8601 %>
82
67
 
83
68
 
84
- === Or as a plugin:
69
+ Forget the ISO 8601 formatting and you'll get a string back, instead.
85
70
 
86
- Install:
71
+ But that's just the surface. Where you're manipulating the primitive objects
72
+ that YAML supports most easily, you could have stored complex Ruby objects:
73
+ Pathname, Proc, or anything else.
87
74
 
88
- % script/plugin install git://github.com/stephencelis/app.git
75
+ class App < Configurable
76
+ config.config_path = Rails.root.join("config")
77
+ config.uptime = Proc.new { (Time.now.utc - App.launched_at).seconds }
78
+ config.asset_host = ActiveSupport::StringInquirer.new "amazon"
79
+ end
89
80
 
81
+ App.config_path.join("app") # => #<Pathname:config/app>
82
+ App.uptime.call # => 430.198400 seconds
83
+ App.asset_host.amazon? # => true
90
84
 
91
- Or submodule:
92
85
 
93
- % git submodule add git://github.com/stephencelis/app.git vendor/plugins/app
86
+ And because these configuration files are just class definitions, you can
87
+ write your own methods, as well.
94
88
 
89
+ class App < Configurable
90
+ def self.destroy_sessions!
91
+ Session.delete_all
92
+ end
93
+ end
95
94
 
96
- === Finally, generate:
95
+ App.destroy_sessions! # => 1
97
96
 
98
- % script/generate app_config
99
97
 
98
+ If Ruby can handle it, so can App.
100
99
 
101
- If your "app.yml" gets out of hand, modularize, like in this heavy-handed
102
- example:
100
+ But OK, OK, there's still an upgrade path:
103
101
 
104
- % script/generate app_config apis/twitter
105
- create config/app/apis
106
- create config/app/apis/twitter.yml # Configure me!
102
+ class App < Configurable
103
+ # This must come first.
104
+ self.config = <<YAML
105
+ legacy: <%= "configuration" %>
106
+ YAML
107
107
 
108
+ # config.key = "value"
109
+ end
108
110
 
109
- Namespaces avoid collisions:
110
111
 
111
- App::Apis::Twitter.username
112
+ This is not backwards-compatible. This is only to help ease the transition.
113
+ You will most likely have to upgrade your calls.
112
114
 
113
115
 
114
116
  == LICENSE
115
117
 
116
118
  (The MIT License)
117
119
 
118
- (c) 2009-* Stephen Celis, stephen@stephencelis.com.
120
+ (c) 2009-2010 Stephen Celis, stephen@stephencelis.com.
119
121
 
120
- Permission is hereby granted, free of charge, to any person obtaining a copy
121
- of this software and associated documentation files (the "Software"), to deal
122
- in the Software without restriction, including without limitation the rights
123
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
124
- copies of the Software, and to permit persons to whom the Software is
122
+ Permission is hereby granted, free of charge, to any person obtaining a copy
123
+ of this software and associated documentation files (the "Software"), to deal
124
+ in the Software without restriction, including without limitation the rights
125
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
126
+ copies of the Software, and to permit persons to whom the Software is
125
127
  furnished to do so, subject to the following conditions:
126
128
 
127
129
  The above copyright notice and this permission notice shall be included in all
data/Rakefile CHANGED
@@ -1,23 +1,10 @@
1
- require 'rake'
2
1
  require 'rake/testtask'
3
- require 'rake/rdoctask'
4
2
 
5
3
  desc 'Default: run unit tests.'
6
4
  task :default => :test
7
5
 
8
6
  desc 'Test the app plugin.'
9
7
  Rake::TestTask.new(:test) do |t|
10
- t.libs << 'lib'
11
8
  t.libs << 'test'
12
9
  t.pattern = 'test/**/*_test.rb'
13
- t.verbose = true
14
- end
15
-
16
- desc 'Generate documentation for the app plugin.'
17
- Rake::RDocTask.new(:rdoc) do |rdoc|
18
- rdoc.rdoc_dir = 'rdoc'
19
- rdoc.title = 'App'
20
- rdoc.options << '--line-numbers' << '--inline-source'
21
- rdoc.rdoc_files.include('README.rdoc')
22
- rdoc.rdoc_files.include('lib/**/*.rb')
23
10
  end
data/lib/app.rb CHANGED
@@ -1,73 +1,91 @@
1
- # App is your app.
1
+ # Provides configuration via superclass. Inherit from Configurable, and you
2
+ # have a handy little DSL/class for assigning/accessing your app settings.
2
3
  #
3
- # What would your app be without it? Still an app, but without App.
4
- module App
5
- VERSION = "0.2.2"
4
+ # class App < Configurable
5
+ # config.launched_at = Time.now.utc
6
+ # end
7
+ #
8
+ # App.launched_at # => 2010-02-21 12:34:56 UTC
9
+ #
10
+ # Configurable classes will warn you when you call undefined settings.
11
+ #
12
+ # App.typo # => nil
13
+ # warning: undefined setting `typo' for App:Class
14
+ #
15
+ # If you don't care about these warnings, just redefine the logger.
16
+ #
17
+ # App.configure do
18
+ # config.logger = Logger.new nil
19
+ # end
20
+ class Configurable
21
+ autoload :Logger, "logger"
22
+ autoload :OpenStruct, "ostruct"
23
+
24
+ # Deprecated autoloads.
25
+ autoload :ERB, "erb"
26
+ autoload :YAML, "yaml"
6
27
 
7
- @@config = {} # Initialize.
8
28
  class << self
9
- # Returns the application configuration hash, as defined in
10
- # "config/app.yml".
11
- #
12
- # Follows args through the hash tree. E.g.:
13
- #
14
- # App.config("apis", "flickr") # => config_hash["apis"]["flickr"]
15
- #
16
- # <tt>App.config</tt> is aliased to <tt>App.[]</tt>, so shorten things up:
17
- #
18
- # App["apis", "flickr"]
19
- #
20
- # Or rely on +method_missing+ to make it even shorter (and sweeter):
21
- #
22
- # App.apis("flickr")
23
- def config(*args)
24
- @@config if args.empty?
25
- args.inject(@@config) { |config, arg| config[arg] }
29
+ alias __name__ name
30
+ undef name
31
+
32
+ alias configure class_eval
33
+
34
+ def [](key)
35
+ unless config.respond_to? key
36
+ logger.warn "warning: undefined setting `#{key}' for #{__name__}:Class"
37
+ end
38
+
39
+ config.send key
26
40
  end
27
- alias [] config
28
41
 
29
42
  def inspect
30
- "#<#{name}: #{config.inspect}>"
43
+ config.inspect.sub config.class.name, __name__
44
+ end
45
+
46
+ def logger
47
+ return config.logger if config.respond_to? :logger
48
+ @logger ||= defined?(Rails) ? Rails.logger : Logger.new(STDERR)
31
49
  end
32
50
 
33
51
  private
34
52
 
35
- def method_missing(method, *args)
36
- self[method.to_s, *args] || self[method, *args]
53
+ def config
54
+ @config ||= OpenStruct.new
37
55
  end
38
- end
39
-
40
- begin
41
- raw = File.read Rails.root.join("config", "#{name.underscore}.yml")
42
- all = YAML.load ERB.new(raw).result
43
- @@config = all[Rails.env] || all
44
- @@config.freeze
45
- rescue Errno::ENOENT => e
46
- puts '** App: no file "config/app.yml". Run `script/generate app_config`.'
47
- end
48
- end
49
56
 
50
- unless __FILE__ == "(eval)"
51
- module App
52
- class << self
53
- # Returns the name of the web application.
54
- def to_s
55
- File.basename Rails.root
57
+ def config=(settings)
58
+ @config = case settings
59
+ when String
60
+ logger.warn "warning: YAML is deprecated (#{__FILE__}:#{__LINE__})"
61
+ OpenStruct.new YAML.load(ERB.new(settings).result)
62
+ when Hash
63
+ OpenStruct.new settings
64
+ else
65
+ settings
56
66
  end
57
67
  end
68
+
69
+ def method_missing(method, *args, &block)
70
+ super if (key = method.to_s).end_with?("=")
71
+ boolean = key.chomp!("?")
72
+ value = self[key]
73
+ value = value.call(*args, &block) if value.respond_to?(:call)
74
+ boolean ? !!value : value
75
+ end
58
76
  end
59
77
 
60
- # Iterate through other App configs and namespace them.
61
- Dir[Rails.root.join("config", "app", "**/*.yml")].sort.each do |config|
62
- name = config.gsub(/#{Rails.root.join("config")}\/|\.yml/) {}.classify
78
+ if defined? Rails
79
+ class Plugin < Rails::Railtie # :nodoc:
80
+ railtie_name :configurable
63
81
 
64
- # Recognize all parents.
65
- line = name.split "::"
66
- line.inject line.shift do |parentage, descendant|
67
- eval "module #{parentage}; end"
68
- "#{parentage}::#{descendant}"
82
+ initializer "configurable.require_app" do |app|
83
+ begin
84
+ require app.root.join "config", "app"
85
+ require app.root.join "config", "app", Rails.env
86
+ rescue LoadError
87
+ end
88
+ end
69
89
  end
70
-
71
- eval File.read(__FILE__).sub("module App", "module #{name}")
72
90
  end
73
91
  end
@@ -0,0 +1,13 @@
1
+ class ConfigurableGenerator < Rails::Generators::Base # :nodoc:
2
+ def self.source_root
3
+ @_configurable_source_root ||=
4
+ File.expand_path("../#{base_name}/templates", __FILE__)
5
+ end
6
+
7
+ def install
8
+ copy_file "app.rb", "config/app.rb"
9
+ Dir[Rails.root.join("config", "environments", "*.rb").to_s].each do |env|
10
+ template "app/env.rb", "config/app/#{File.basename env}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ class App < Configurable # :nodoc:
2
+ # Settings in config/app/* take precedence over those specified here.
3
+ config.name = Rails::Application.instance.class.parent.name
4
+
5
+ # config.key = "value"
6
+ end
@@ -0,0 +1,5 @@
1
+ App.configure do
2
+ # Settings specified here will take precedence over those in config/app.rb
3
+
4
+ # config.key = "value"
5
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: app
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Celis
@@ -9,43 +9,27 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-17 00:00:00 -05:00
12
+ date: 2010-02-21 00:00:00 -06:00
13
13
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: hoe
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 1.12.0
24
- version:
25
- description: Move the config out of your app, and into App. Sure, it's been done before, and others will do it again, but this is my way, and I like it.
26
- email:
27
- - stephen@stephencelis.com
14
+ dependencies: []
15
+
16
+ description: Move the config out of your app, and into App.
17
+ email: stephen@stephencelis.com
28
18
  executables: []
29
19
 
30
20
  extensions: []
31
21
 
32
22
  extra_rdoc_files:
33
23
  - History.rdoc
34
- - Manifest.txt
35
24
  - README.rdoc
36
25
  files:
37
26
  - History.rdoc
38
- - Manifest.txt
39
27
  - README.rdoc
40
28
  - Rakefile
41
- - generators/app_config/app_config_generator.rb
42
- - generators/app_config/templates/app.yml
43
- - install.rb
44
29
  - lib/app.rb
45
- - test/app_test.rb
46
- - test/fixtures/app/authenticate/basic/config.yml
47
- - test/fixtures/app/authenticate.yml
48
- - test/fixtures/app.yml
30
+ - lib/generators/configurable_generator/templates/app/env.rb
31
+ - lib/generators/configurable_generator/templates/app.rb
32
+ - lib/generators/configurable_generator.rb
49
33
  has_rdoc: true
50
34
  homepage: http://github.com/stephencelis/app
51
35
  licenses: []
@@ -70,10 +54,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
54
  version:
71
55
  requirements: []
72
56
 
73
- rubyforge_project: app
57
+ rubyforge_project:
74
58
  rubygems_version: 1.3.5
75
59
  signing_key:
76
60
  specification_version: 3
77
- summary: Move the config out of your app, and into App
61
+ summary: Application configuration.
78
62
  test_files: []
79
63
 
@@ -1,12 +0,0 @@
1
- History.rdoc
2
- Manifest.txt
3
- README.rdoc
4
- Rakefile
5
- generators/app_config/app_config_generator.rb
6
- generators/app_config/templates/app.yml
7
- install.rb
8
- lib/app.rb
9
- test/app_test.rb
10
- test/fixtures/app/authenticate/basic/config.yml
11
- test/fixtures/app/authenticate.yml
12
- test/fixtures/app.yml
@@ -1,32 +0,0 @@
1
- class AppConfigGenerator < Rails::Generator::Base
2
- def manifest
3
- record do |m|
4
- if ARGV.empty?
5
- if File.exist? Rails.root.join("config", "app.yml")
6
- show_banner
7
- else
8
- m.file "app.yml", "config/app.yml"
9
- end
10
- else
11
- ARGV.each do |arg|
12
- path = "config/app/#{arg.underscore}"
13
- m.directory File.dirname(path)
14
- m.file "app.yml", "#{path}.yml"
15
- end
16
- end
17
- end
18
- end
19
-
20
- private
21
-
22
- def show_banner
23
- puts "App: you already have an app.yml!"
24
- puts
25
- puts " Remember to pass arguments to generate new configurations:"
26
- puts " script/generate app_config apis/twitter"
27
- puts
28
- puts " Generates:"
29
- puts " config/app/apis"
30
- puts " config/app/apis/twitter.yml"
31
- end
32
- end
@@ -1,18 +0,0 @@
1
- # An app config, provided by App: http://github.com/stephencelis/app
2
- ---
3
- development: &development
4
- loaded_at: <%= Time.zone.now.iso8601 %>
5
- apis:
6
- braintree:
7
- :login: testapi
8
- :password: password1
9
-
10
- test:
11
- <<: *development
12
-
13
- production:
14
- loaded_at: <%= Time.zone.now.iso8601 %>
15
- apis:
16
- braintree:
17
- :login: testapi
18
- :password: password1
data/install.rb DELETED
@@ -1 +0,0 @@
1
- $stdout.puts 'Run `script/generate app_config` to generate "config/app.yml".'
@@ -1,64 +0,0 @@
1
- require 'test/unit'
2
- require 'rubygems'
3
- require 'active_support'
4
- require 'active_support/test_case'
5
- require 'mocha'
6
- require 'erb'
7
-
8
- # Mock!
9
- module Rails
10
- def self.root
11
- self
12
- end
13
- def self.join(*args)
14
- args.shift # No "config" dir, OK?
15
- File.expand_path File.join(File.dirname(__FILE__), "fixtures", *args)
16
- end
17
- def self.env
18
- "development"
19
- end
20
- end
21
-
22
- # And load!
23
- require 'app'
24
-
25
- class AppTest < ActiveSupport::TestCase
26
- test "should access many ways" do
27
- assert_equal "Welcome!", App.config["welcome_message"]
28
- assert_equal "Welcome!", App.config("welcome_message")
29
- assert_equal "Welcome!", App["welcome_message"]
30
- assert_equal "Welcome!", App.welcome_message
31
-
32
- assert_equal "testapi", App.config["apis"]["braintree"][:login]
33
- assert_equal "testapi", App.config("apis", "braintree", :login)
34
- assert_equal "testapi", App["apis", "braintree", :login]
35
- assert_equal "testapi", App.apis("braintree", :login)
36
- end
37
-
38
- test "should parse ERB" do
39
- assert_instance_of Time, App.loaded_at
40
- end
41
-
42
- test "should accept boolean keys" do
43
- assert !App.process_payments?
44
- end
45
-
46
- test "should infer App.name" do
47
- File.stubs(:basename).returns "root"
48
- assert_equal "root", App.to_s
49
- end
50
-
51
- test "should namespace configs" do
52
- assert_instance_of Module, App::Authenticate
53
- assert_equal "frobozz", App::Authenticate["Stephen"]
54
- end
55
-
56
- test "should nest multiple levels of configs" do
57
- assert_instance_of Module, App::Authenticate::Basic::Config
58
- assert_equal :basic, App::Authenticate::Basic::Config.authentication_type
59
- end
60
-
61
- test "should be frozen" do
62
- assert_raise(TypeError) { App.config["loaded_at"] = Time.now }
63
- end
64
- end
@@ -1,9 +0,0 @@
1
- ---
2
- development:
3
- loaded_at: <%= Time.now.iso8601 %>
4
- welcome_message: Welcome!
5
- process_payments?: false
6
- apis:
7
- braintree:
8
- :login: testapi
9
- :password: password1
@@ -1,4 +0,0 @@
1
- ---
2
- development:
3
- Stephen: frobozz
4
- housemd: God
@@ -1,2 +0,0 @@
1
- ---
2
- authentication_type: :basic