dice_bag 0.4.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/lib/dice_bag.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative 'dice_bag/available_templates'
2
+ module DiceBag
3
+ require 'dice_bag/railtie' if defined?(Rails)
4
+ end
@@ -0,0 +1,45 @@
1
+ # This class returns all the templates we can generate in this particular project
2
+ module DiceBag
3
+
4
+ class AvailableTemplates
5
+
6
+ class << self
7
+
8
+ def template_checkers
9
+ @template_checkers ||= []
10
+ end
11
+
12
+ def inherited(base)
13
+ template_checkers << base
14
+ end
15
+
16
+ def all
17
+ #all the classes than inherit from us in the ruby runtime
18
+ available_templates = []
19
+
20
+ template_checkers.each do |checker|
21
+ checker.new.templates.each do |template|
22
+ available_templates.push( template)
23
+ end
24
+ end
25
+ available_templates
26
+ end
27
+
28
+ def template_filename_for(filename)
29
+ self.all.each do |template_filename|
30
+ if template_filename.include? filename
31
+ return template_filename
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+
41
+
42
+ # we require the our own templates checker here, for other gems we just need
43
+ # them to inherit from DiceBag::AvailableTemplates and require the file
44
+ # If Ruby loads the file we can find the class in the object space and call it
45
+ require_relative 'templates/gems_checker'
@@ -0,0 +1,43 @@
1
+ require 'dice_bag/available_templates'
2
+ require 'dice_bag/project'
3
+ require 'dice_bag/config_file'
4
+ require 'dice_bag/template_file'
5
+ require 'dice_bag/default_template_file'
6
+
7
+ module DiceBag
8
+ #This class seems a candidate to be converted to Thor, the problem is that we need to run
9
+ #in the same process than the rake task so all the gems are loaded before dice_bag
10
+ #is called and dice_bag can find what software is used in this project
11
+ class Command
12
+
13
+ def write_all
14
+ Project.templates_to_generate.each do |template|
15
+ write(template)
16
+ end
17
+ end
18
+
19
+ def write(template_name)
20
+ template_file = TemplateFile.new(template_name)
21
+ template_file.assert_existence
22
+ config_file = ConfigFile.new(template_name)
23
+
24
+ template_file.create_file(config_file)
25
+ end
26
+
27
+
28
+ def generate_all_templates
29
+ AvailableTemplates.all.each do |template|
30
+ generate_template(template)
31
+ end
32
+ end
33
+
34
+ def generate_template(file)
35
+ default_template = DefaultTemplateFile.new(file)
36
+ default_template.assert_existence
37
+ project_template = TemplateFile.new(File.basename(file))
38
+
39
+ default_template.create_file(project_template)
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,14 @@
1
+ require 'dice_bag/dice_bag_file.rb'
2
+ require 'dice_bag/project'
3
+
4
+ #this class encapsulate a configuration file of the project
5
+ module DiceBag
6
+
7
+ class ConfigFile
8
+ include DiceBagFile
9
+ def initialize(name)
10
+ @filename = name.gsub('.local', '').gsub('.erb', '').gsub('.template','')
11
+ @file = @filename
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ module DiceBag
2
+
3
+ # This class abstracts access to configuration values, to be used within ERB
4
+ # templates. Currently, the values are read from the environment, as per the
5
+ # Twelve-Factor App principles.
6
+ class Configuration
7
+
8
+ def initialize
9
+ @prefixed = Hash.new
10
+ end
11
+
12
+ # Returns a Configuration::PrefixedWithFallback using the given +prefix+.
13
+ #
14
+ def [](prefix)
15
+ @prefixed[prefix] ||= PrefixedWithFallback.new(prefix, self)
16
+ end
17
+
18
+ def method_missing(name)
19
+ ENV[name.to_s.upcase]
20
+ end
21
+
22
+ # This class acts like +Configuration+ but with a prefix applied to the
23
+ # environment variables used to provide values. This is useful for providing
24
+ # per-environment overrides to value in Rails projects. If the prefixed
25
+ # environment variable is not found, the class delegates to the provided
26
+ # fallback Configuration class, without the prefix.
27
+ #
28
+ class PrefixedWithFallback
29
+ def initialize(prefix, fallback)
30
+ @prefix = prefix.to_s.upcase
31
+ @fallback = fallback
32
+ end
33
+
34
+ def method_missing(name)
35
+ ENV["#{ @prefix }_#{ name.to_s.upcase }"] || @fallback.send(name)
36
+ end
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,34 @@
1
+ require 'dice_bag/dice_bag_file'
2
+ require 'dice_bag/project'
3
+
4
+ require 'tempfile'
5
+
6
+ #This file encapsulate the template files Dicebag brings with itself
7
+ module DiceBag
8
+
9
+ class DefaultTemplateFile
10
+ include DiceBagFile
11
+
12
+ def initialize(name)
13
+ #if called from command line with only a name we search in all our templates for the file
14
+ if (File.dirname(name) == '.')
15
+ name = AvailableTemplates.template_filename_for(name)
16
+ end
17
+ @filename = File.basename(name)
18
+ @file = name
19
+ end
20
+
21
+ def create_file(template_file)
22
+ contents = read_template(@file)
23
+ template_file.write(contents)
24
+ puts "new template file generated in #{template_file.file}.
25
+ execute 'rake config:all' to get the corresponding configuration file."
26
+ end
27
+
28
+ def read_template(template)
29
+ # Some templates need the name of the project. We put a placeholder
30
+ # PROJECT_NAME there, it gets substituted by the real name of the project here
31
+ File.readlines(template).join.gsub("PROJECT_NAME", Project.name)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,59 @@
1
+ require 'dice_bag/version'
2
+
3
+ # This module contains common methods for all the type of files Dicebag knows about:
4
+ # configuration files, templates files in the project an templates files shipped with dicebag
5
+ module DiceBag
6
+ module DiceBagFile
7
+ attr_reader :file, :filename
8
+ @@force = false
9
+
10
+ def assert_existence
11
+ unless File.exists?(@file)
12
+ raise "File #{@file} not found. Configuration file not created"
13
+ end
14
+ end
15
+
16
+ def write(contents)
17
+ File.open(@file, 'w') do |file|
18
+ file.puts(contents)
19
+ end
20
+ end
21
+
22
+ def should_write?(new_contents)
23
+ #we always overwrite if we are inside an script or we are not development
24
+ return true if @@force || !$stdin.tty? || ENV['RAILS_ENV'] == 'test' || ENV['RAILS_ENV'] == 'production'
25
+ return true if !File.exists?(file)
26
+ return false if diff(file, new_contents).empty?
27
+
28
+ while true
29
+ puts "Overwrite #{file} ? Recommended: Yes. "
30
+ puts " [Y]es, [n]o, [a]ll files, [q]uit, [d]show diff"
31
+ answer = $stdin.gets.tap{|text| text.strip!.downcase! if text}
32
+ case answer
33
+ when 'y'
34
+ return true
35
+ when 'n'
36
+ return false
37
+ when 'a'
38
+ return @@force = true
39
+ when 'q'
40
+ exit
41
+ when 'd'
42
+ puts diff(file, new_contents)
43
+ else
44
+ return true
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+ def diff(destination, content)
51
+ diff_cmd = ENV['RAILS_DIFF'] || 'diff -u'
52
+ Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
53
+ temp.write content
54
+ temp.rewind
55
+ `#{diff_cmd} #{destination} #{temp.path}`.strip
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,27 @@
1
+ #This class encapsulate data about the project dice_bag got in
2
+ module DiceBag
3
+
4
+ class Project
5
+
6
+ DEFAULT_NAME = 'project'
7
+ def self.name
8
+ #TODO: how to do find the name of the project in no-rails environments?
9
+ defined?(Rails) ? Rails.application.class.parent_name.downcase : DEFAULT_NAME
10
+ end
11
+
12
+ def self.config_files(filename)
13
+ File.join(Dir.pwd, filename)
14
+ end
15
+
16
+ #local templates always takes preference over generated templates
17
+ def self.templates_to_generate
18
+ generated_templates = Dir[Project.config_files("**/config/*.erb")]
19
+ custom_templates = Dir[Project.config_files("**/config/*.erb.local")]
20
+ dotNetTemplates = Dir[Project.config_files("**/*.config.template")]
21
+ all_files = generated_templates + custom_templates
22
+ templates = all_files.delete_if {|file| custom_templates.include?(file + '.local')}
23
+ dotNetTemplates = dotNetTemplates.delete_if {|file| file.include?("/bin/")}
24
+ all_files + dotNetTemplates
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ module DiceBag
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ require 'dice_bag/tasks'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ load 'dice_bag/tasks/config.rake'
@@ -0,0 +1,31 @@
1
+ require 'erb'
2
+ require 'dice_bag/command'
3
+
4
+ desc "Configure the application from the environment. It creates template files if you need and their config files"
5
+ task :config => ['config:generate_all', 'config:all']
6
+
7
+ namespace :config do
8
+ desc "Create all the files from their templates in config/"
9
+ task :all do
10
+ DiceBag::Command.new.write_all
11
+ end
12
+
13
+ desc "Recreate the file passed as parameter from its template"
14
+ task :file, :filename do |t, args|
15
+ filename = args[:filename]
16
+ raise "A filename needs to be provided" if filename.nil?
17
+ DiceBag::Command.new.write(filename)
18
+ end
19
+
20
+ desc "Generates all the template files needed by this project, named as the parameter."
21
+ task :generate_all do
22
+ DiceBag::Command.new.generate_all_templates
23
+ end
24
+
25
+ desc "Regenerate a given template"
26
+ task :generate, :filename do |t, args|
27
+ filename = args[:filename]
28
+ raise "A filename needs to be provided" if filename.nil?
29
+ DiceBag::Command.new.generate_template(filename)
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ require 'dice_bag/dice_bag_file.rb'
2
+ require 'dice_bag/template_helpers'
3
+ require 'dice_bag/configuration'
4
+ require 'dice_bag/warning'
5
+
6
+ #this class encapsulates the template files we will generate in the project
7
+ #using this gem
8
+ module DiceBag
9
+
10
+ class TemplateFile
11
+ include DiceBagFile
12
+
13
+ # Methods from this module need to be called directly from within the ERB
14
+ # templates.
15
+ include DiceBag::TemplateHelpers
16
+
17
+ def initialize(name)
18
+ @filename = File.basename(name)
19
+ @file = name
20
+ end
21
+
22
+ def create_file(config_file)
23
+ # By passing "<>" we're trimming trailing newlines on lines that are
24
+ # nothing but ERB blocks (see documentation). This is useful for files
25
+ # like mauth_key where we want to control newlines carefully.
26
+ template = ERB.new(File.read(@file), nil, "<>")
27
+
28
+ #templates expect a configured object
29
+ configured = Configuration.new
30
+ warning = Warning.new(@filename)
31
+ contents = template.result(binding)
32
+
33
+ return unless config_file.should_write?(contents)
34
+ config_file.write(contents)
35
+ puts "file #{config_file.file} created"
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,8 @@
1
+ module DiceBag
2
+ module TemplateHelpers
3
+ def generate_private_key
4
+ require 'openssl'
5
+ OpenSSL::PKey::RSA.generate(2048)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ <%= warning.as_yaml_comment %>
2
+
3
+ development: &default
4
+ access_key_id: <%= configured.aws_access_key_id %>
5
+ secret_access_key: <%= configured.aws_secret_access_key %>
6
+
7
+ test:
8
+ <<: *default
9
+
10
+ production:
11
+ <<: *default
@@ -0,0 +1,20 @@
1
+ <%= warning.as_yaml_comment %>
2
+
3
+ # This example file is intended to be used by a the developer who would like
4
+ # use a locally running memcached. By default, though,
5
+ # config/environments/development.rb sets the cache_store to memory
6
+ # To enable this storage mechanism in development mode, consult the
7
+ # cache configuration code in config/environments/production.rb
8
+
9
+ development: &default
10
+ namespace: PROJECT_NAME
11
+ host: localhost
12
+ port: 11211
13
+ value_max_bytes: 52428800
14
+ compress: true
15
+
16
+ test:
17
+ <<: *default
18
+
19
+ production:
20
+ <<: *default
@@ -0,0 +1,16 @@
1
+ <%= warning.as_yaml_comment %>
2
+
3
+ <% [:development, :test, :production].each do |env| %>
4
+ <%= env %>:
5
+ adapter: <%= configured[env].database_driver || 'mysql2' %>
6
+ database: <%= configured[env].database_name || "PROJECT_NAME_#{env}" %>
7
+ username: <%= configured[env].database_username || 'root' %>
8
+ password: <%= configured[env].database_password %>
9
+ host: <%= configured[env].database_host || 'localhost' %>
10
+ pool: 5
11
+ timeout: 5000
12
+ encoding: utf8
13
+ reconnect: false
14
+ <% db_cert = configured[env].database_ssl_cert %>
15
+ <%= db_cert ? "sslca: #{db_cert}" : '' %>
16
+ <% end %>
@@ -0,0 +1,44 @@
1
+ # This module has the logic that decides what templates will be
2
+ # generated for this project.
3
+ # this file lives in the same directory than all the templates it
4
+ # provides logic for.
5
+ require 'dice_bag'
6
+
7
+ module DiceBag
8
+ class CommonTemplatesBag < AvailableTemplates
9
+
10
+ def templates
11
+ @needed_templates = []
12
+ configured = Configuration.new
13
+
14
+ if defined?(Dalli)
15
+ add_template('dalli.yml.erb')
16
+ end
17
+
18
+ if defined?(Mysql2)
19
+ add_template('database.yml.erb')
20
+ end
21
+
22
+ if defined?(AWS)
23
+ add_template('aws.yml.erb')
24
+ end
25
+
26
+ if configured.google_analytics_id
27
+ add_template('google_analytics.yml.erb')
28
+ end
29
+
30
+ if defined?(NewRelic)
31
+ add_template('newrelic.yml.erb')
32
+ end
33
+
34
+ @needed_templates
35
+ end
36
+
37
+ def add_template(file)
38
+ pwd = File.dirname(__FILE__)
39
+ @needed_templates.push(File.join(pwd, file))
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,5 @@
1
+ <%= warning.as_yaml_comment %>
2
+
3
+ <% if configured.google_analytics_id %>
4
+ <%= "#{configured.rails_env}: #{configured.google_analytics_id}" %>
5
+ <% end %>
@@ -0,0 +1,37 @@
1
+ <%= warning.as_yaml_comment %>
2
+
3
+ common: &default_settings
4
+ license_key: <%= configured.newrelic_key || "12345" %>
5
+ app_name: <%= configured.domain || 'PROJECT_NAME' %>
6
+ enabled: <%= configured.enable_newrelic || false %>
7
+ log_level: <%= configured.new_relic_debug == 'true' ? 'debug' : 'info' %>
8
+ ssl: false
9
+ apdex_t: 0.5
10
+ capture_params: false
11
+ transaction_tracer:
12
+ enabled: true
13
+ transaction_threshold: apdex_f
14
+ record_sql: obfuscated
15
+ stack_trace_threshold: <%= configured.new_relic_debug == 'true' ? '0.1' : '0.5' %>
16
+ error_collector:
17
+ enabled: true
18
+ capture_source: true
19
+ ignore_errors: ActionController::RoutingError
20
+ background:
21
+ monitor_mode: true
22
+ app_name: <%= configured.domain || 'PROJECT_NAME' %>
23
+
24
+ development:
25
+ <<: *default_settings
26
+ enabled: false
27
+ developer: true
28
+
29
+ test:
30
+ <<: *default_settings
31
+ enabled: false
32
+ developer: false
33
+
34
+ production:
35
+ <<: *default_settings
36
+ enabled: true
37
+ developer: false
@@ -0,0 +1,3 @@
1
+ module DiceBag
2
+ VERSION = '0.4.0'
3
+ end
@@ -0,0 +1,30 @@
1
+ module DiceBag
2
+ class Warning
3
+
4
+ def initialize(template_filename)
5
+ @template_filename = template_filename
6
+ end
7
+
8
+ def as_ruby_comment
9
+ lines.map {|line| "# #{line}\n" }.join
10
+ end
11
+
12
+ alias :as_yaml_comment :as_ruby_comment
13
+
14
+ def as_xml_comment
15
+ ['<!--', lines, '-->'].flatten.join("\n")
16
+ end
17
+
18
+ protected
19
+
20
+ def lines
21
+ [
22
+ "WARNING! Do not modify this file directly. It was generated from the",
23
+ "'#@template_filename' template file.",
24
+ "",
25
+ "Use the rake config task to reconfigure. See the template file for",
26
+ "further guidance."
27
+ ]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+ require 'dice_bag/project'
3
+
4
+ describe DiceBag::Project do
5
+ let(:project) { DiceBag::Project }
6
+
7
+ describe "#name" do
8
+ it "should give me a default name for non Rails apps" do
9
+ project.name.should == DiceBag::Project::DEFAULT_NAME
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,12 @@
1
+ # Require this file using `require "spec_helper"` to ensure that it is only
2
+ # loaded once.
3
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
4
+ require 'dice_bag'
5
+ require 'rspec'
6
+
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+ config.order = 'random'
12
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dice_bag
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Andrew Smith
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-14 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &73429760 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *73429760
25
+ description:
26
+ email:
27
+ - asmith@mdsol.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - lib/dice_bag.rb
33
+ - lib/dice_bag/warning.rb
34
+ - lib/dice_bag/command.rb
35
+ - lib/dice_bag/project.rb
36
+ - lib/dice_bag/default_template_file.rb
37
+ - lib/dice_bag/tasks.rb
38
+ - lib/dice_bag/template_file.rb
39
+ - lib/dice_bag/dice_bag_file.rb
40
+ - lib/dice_bag/config_file.rb
41
+ - lib/dice_bag/version.rb
42
+ - lib/dice_bag/templates/newrelic.yml.erb
43
+ - lib/dice_bag/templates/database.yml.erb
44
+ - lib/dice_bag/templates/gems_checker.rb
45
+ - lib/dice_bag/templates/google_analytics.yml.erb
46
+ - lib/dice_bag/templates/dalli.yml.erb
47
+ - lib/dice_bag/templates/aws.yml.erb
48
+ - lib/dice_bag/railtie.rb
49
+ - lib/dice_bag/configuration.rb
50
+ - lib/dice_bag/tasks/config.rake
51
+ - lib/dice_bag/available_templates.rb
52
+ - lib/dice_bag/template_helpers.rb
53
+ - spec/command_spec.rb
54
+ - spec/spec_helper.rb
55
+ homepage: https://github.com/mdsol/dice_bag
56
+ licenses: []
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 1.8.15
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Dice Bag is a library of rake tasks for configuring web apps in the style
79
+ of The Twelve-Factor App. It also provides continuous integration tasks that rely
80
+ on the configuration tasks.
81
+ test_files:
82
+ - spec/command_spec.rb
83
+ - spec/spec_helper.rb