settei 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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.yardopts +2 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +134 -0
- data/README.md +97 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/settei.rb +4 -0
- data/lib/settei/base.rb +61 -0
- data/lib/settei/extensions/host_url.rb +25 -0
- data/lib/settei/generators/rails.rb +113 -0
- data/lib/settei/loaders/simple_loader.rb +85 -0
- data/lib/settei/railtie.rb +7 -0
- data/lib/settei/version.rb +3 -0
- data/lib/tasks/settei_tasks.rake +11 -0
- data/settei.gemspec +29 -0
- data/templates/_capistrano.rb +7 -0
- data/templates/_mina.rb +9 -0
- data/templates/setting.rb +13 -0
- data/templates/setting.yml +1 -0
- metadata +122 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 8d7db95b9bd55c016fd36a30e28f42d6c360fadf
|
|
4
|
+
data.tar.gz: 6a6638dc0f1403b4070bdfde0ec9194f52683f44
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6a052e47b595948163a00b02a1138b09124acbff2d3fce28cf5882d5f6e2761899ff8c9cd065623e26186a0abb72e0e12073e06af66698dcf6cc473ec9f927e6
|
|
7
|
+
data.tar.gz: '094233cf0983684d86bf189e1b4a18119335356a992e5a4d7859d93da4bf1bed70bf6f9608257809fc8a00f812323df06e9dd131d98bc2289271eabc1e4dab41'
|
data/.gitignore
ADDED
data/.rspec
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--require spec_helper
|
data/.yardopts
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
settei (0.1.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
actioncable (5.1.4)
|
|
10
|
+
actionpack (= 5.1.4)
|
|
11
|
+
nio4r (~> 2.0)
|
|
12
|
+
websocket-driver (~> 0.6.1)
|
|
13
|
+
actionmailer (5.1.4)
|
|
14
|
+
actionpack (= 5.1.4)
|
|
15
|
+
actionview (= 5.1.4)
|
|
16
|
+
activejob (= 5.1.4)
|
|
17
|
+
mail (~> 2.5, >= 2.5.4)
|
|
18
|
+
rails-dom-testing (~> 2.0)
|
|
19
|
+
actionpack (5.1.4)
|
|
20
|
+
actionview (= 5.1.4)
|
|
21
|
+
activesupport (= 5.1.4)
|
|
22
|
+
rack (~> 2.0)
|
|
23
|
+
rack-test (>= 0.6.3)
|
|
24
|
+
rails-dom-testing (~> 2.0)
|
|
25
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
26
|
+
actionview (5.1.4)
|
|
27
|
+
activesupport (= 5.1.4)
|
|
28
|
+
builder (~> 3.1)
|
|
29
|
+
erubi (~> 1.4)
|
|
30
|
+
rails-dom-testing (~> 2.0)
|
|
31
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
|
32
|
+
activejob (5.1.4)
|
|
33
|
+
activesupport (= 5.1.4)
|
|
34
|
+
globalid (>= 0.3.6)
|
|
35
|
+
activemodel (5.1.4)
|
|
36
|
+
activesupport (= 5.1.4)
|
|
37
|
+
activerecord (5.1.4)
|
|
38
|
+
activemodel (= 5.1.4)
|
|
39
|
+
activesupport (= 5.1.4)
|
|
40
|
+
arel (~> 8.0)
|
|
41
|
+
activesupport (5.1.4)
|
|
42
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
43
|
+
i18n (~> 0.7)
|
|
44
|
+
minitest (~> 5.1)
|
|
45
|
+
tzinfo (~> 1.1)
|
|
46
|
+
arel (8.0.0)
|
|
47
|
+
builder (3.2.3)
|
|
48
|
+
concurrent-ruby (1.0.5)
|
|
49
|
+
crass (1.0.3)
|
|
50
|
+
diff-lcs (1.3)
|
|
51
|
+
erubi (1.7.0)
|
|
52
|
+
globalid (0.4.1)
|
|
53
|
+
activesupport (>= 4.2.0)
|
|
54
|
+
i18n (0.9.4)
|
|
55
|
+
concurrent-ruby (~> 1.0)
|
|
56
|
+
loofah (2.2.0)
|
|
57
|
+
crass (~> 1.0.2)
|
|
58
|
+
nokogiri (>= 1.5.9)
|
|
59
|
+
mail (2.7.0)
|
|
60
|
+
mini_mime (>= 0.1.1)
|
|
61
|
+
method_source (0.9.0)
|
|
62
|
+
mini_mime (1.0.0)
|
|
63
|
+
mini_portile2 (2.3.0)
|
|
64
|
+
minitest (5.11.3)
|
|
65
|
+
nio4r (2.2.0)
|
|
66
|
+
nokogiri (1.8.2)
|
|
67
|
+
mini_portile2 (~> 2.3.0)
|
|
68
|
+
rack (2.0.4)
|
|
69
|
+
rack-test (0.8.2)
|
|
70
|
+
rack (>= 1.0, < 3)
|
|
71
|
+
rails (5.1.4)
|
|
72
|
+
actioncable (= 5.1.4)
|
|
73
|
+
actionmailer (= 5.1.4)
|
|
74
|
+
actionpack (= 5.1.4)
|
|
75
|
+
actionview (= 5.1.4)
|
|
76
|
+
activejob (= 5.1.4)
|
|
77
|
+
activemodel (= 5.1.4)
|
|
78
|
+
activerecord (= 5.1.4)
|
|
79
|
+
activesupport (= 5.1.4)
|
|
80
|
+
bundler (>= 1.3.0)
|
|
81
|
+
railties (= 5.1.4)
|
|
82
|
+
sprockets-rails (>= 2.0.0)
|
|
83
|
+
rails-dom-testing (2.0.3)
|
|
84
|
+
activesupport (>= 4.2.0)
|
|
85
|
+
nokogiri (>= 1.6)
|
|
86
|
+
rails-html-sanitizer (1.0.3)
|
|
87
|
+
loofah (~> 2.0)
|
|
88
|
+
railties (5.1.4)
|
|
89
|
+
actionpack (= 5.1.4)
|
|
90
|
+
activesupport (= 5.1.4)
|
|
91
|
+
method_source
|
|
92
|
+
rake (>= 0.8.7)
|
|
93
|
+
thor (>= 0.18.1, < 2.0)
|
|
94
|
+
rake (10.5.0)
|
|
95
|
+
rspec (3.7.0)
|
|
96
|
+
rspec-core (~> 3.7.0)
|
|
97
|
+
rspec-expectations (~> 3.7.0)
|
|
98
|
+
rspec-mocks (~> 3.7.0)
|
|
99
|
+
rspec-core (3.7.1)
|
|
100
|
+
rspec-support (~> 3.7.0)
|
|
101
|
+
rspec-expectations (3.7.0)
|
|
102
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
103
|
+
rspec-support (~> 3.7.0)
|
|
104
|
+
rspec-mocks (3.7.0)
|
|
105
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
106
|
+
rspec-support (~> 3.7.0)
|
|
107
|
+
rspec-support (3.7.1)
|
|
108
|
+
sprockets (3.7.1)
|
|
109
|
+
concurrent-ruby (~> 1.0)
|
|
110
|
+
rack (> 1, < 3)
|
|
111
|
+
sprockets-rails (3.2.1)
|
|
112
|
+
actionpack (>= 4.0)
|
|
113
|
+
activesupport (>= 4.0)
|
|
114
|
+
sprockets (>= 3.0.0)
|
|
115
|
+
thor (0.20.0)
|
|
116
|
+
thread_safe (0.3.6)
|
|
117
|
+
tzinfo (1.2.5)
|
|
118
|
+
thread_safe (~> 0.1)
|
|
119
|
+
websocket-driver (0.6.5)
|
|
120
|
+
websocket-extensions (>= 0.1.0)
|
|
121
|
+
websocket-extensions (0.1.3)
|
|
122
|
+
|
|
123
|
+
PLATFORMS
|
|
124
|
+
ruby
|
|
125
|
+
|
|
126
|
+
DEPENDENCIES
|
|
127
|
+
bundler (~> 1.16)
|
|
128
|
+
rails
|
|
129
|
+
rake (~> 10.0)
|
|
130
|
+
rspec (~> 3.7.0)
|
|
131
|
+
settei!
|
|
132
|
+
|
|
133
|
+
BUNDLED WITH
|
|
134
|
+
1.16.0
|
data/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Settei
|
|
2
|
+
|
|
3
|
+
Hash based configuration with flexibility and 12-factor app deployment in mind
|
|
4
|
+
|
|
5
|
+
## Design Philosophies
|
|
6
|
+
|
|
7
|
+
* Fast as it is accessible without loading Rails
|
|
8
|
+
* Ease of management as nested hash is allowed
|
|
9
|
+
* 12-factor compatible by serializing as environment variable.
|
|
10
|
+
* Minimal meta-programming magics, so you can add your flavor of magic.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
Add this line to your application's Gemfile:
|
|
15
|
+
|
|
16
|
+
```ruby
|
|
17
|
+
gem 'settei'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
And then execute:
|
|
21
|
+
|
|
22
|
+
$ bundle
|
|
23
|
+
|
|
24
|
+
Or install it yourself as:
|
|
25
|
+
|
|
26
|
+
$ gem install settei
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
For Rails, a rake task is available for simple setup:
|
|
31
|
+
|
|
32
|
+
$ settei:install:rails
|
|
33
|
+
|
|
34
|
+
A `config/setting.rb` file is added for basic setup.
|
|
35
|
+
|
|
36
|
+
YAML files are added under `config/environments` and is ignored by git.
|
|
37
|
+
|
|
38
|
+
In your app, you can access the settings like this:
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
Setting.dig(:google, :api, :secret)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Settei::Base
|
|
45
|
+
|
|
46
|
+
`Settei::Base` is the core class for accessing the configurations. It is initialized by a hash. It is a light wrapper intended for you to extend.
|
|
47
|
+
|
|
48
|
+
`#dig` is used to access its values. It's convenient because it does not err if nested hash is absent.
|
|
49
|
+
|
|
50
|
+
`#dig_and_wrap` will return a `Settei::Base` if it the return value is a hash.
|
|
51
|
+
|
|
52
|
+
Install script maps `Setting` to an instance of `Settei::Base`, for convenience.
|
|
53
|
+
|
|
54
|
+
## Loader
|
|
55
|
+
|
|
56
|
+
`Settei::Loaders::SimpleLoader` is responsible for providing the hash to initialize `Settei::Base`. It loads from a source such as YAML or environment variable. It can also serialize the whole hash into one string, suitable for deploying via environment variables.
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
loader = Settei::Loaders::SimpleLoader.new(dir: 'path/to/dir')
|
|
60
|
+
loader.load.as_hash # loads default.yml and returns a hash
|
|
61
|
+
loader.load(:production).as_env_value # loads production.yml and returns "XYZ"
|
|
62
|
+
loader.load(:test).as_env_assignment # loads test.yml and returns "APP_CONG=XYZ"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
We welcome PRs for different types of loaders, as `SimpleLoader` is not suitable for every situation.
|
|
66
|
+
|
|
67
|
+
## Deployment
|
|
68
|
+
|
|
69
|
+
If `deploy.rb` is present, `rake settei:install:rails` will append code to it, allow serialized config to be passed as an environment variable.
|
|
70
|
+
|
|
71
|
+
## Frameworks other than Rails
|
|
72
|
+
|
|
73
|
+
Settei is designed to be simple so you can integrate it into any frameworks easily. The steps are mainly:
|
|
74
|
+
|
|
75
|
+
1. Designate a folder for storing YAML files.
|
|
76
|
+
2. Create a `setting.rb` file, in which `Settei::Base` is initialized (see `templates/setting.rb`)
|
|
77
|
+
3. Require it when framework starts.
|
|
78
|
+
4. Load and pass serialized production config as environment variable in deploy script (see `templates/_capistrano.rb` or `templates/_mina.rb`).
|
|
79
|
+
|
|
80
|
+
We also welcome PRs for generators of other frameworks too.
|
|
81
|
+
|
|
82
|
+
# Ruby < 2.3
|
|
83
|
+
|
|
84
|
+
`Settei::Base` uses `dig` to access the configuration, available since Ruby 2.3. If your Ruby is not new enough, don't be afraid. Write your own hash accessor literally takes minutes. You can even use `SettingsLogic.new(hash)` .
|
|
85
|
+
|
|
86
|
+
# FAQ
|
|
87
|
+
|
|
88
|
+
**Q:** Would serialized configuration be too big for environment variable?
|
|
89
|
+
**A:** [The upper limit is pretty big.](https://stackoverflow.com/a/1078125/474597)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
## TODO
|
|
93
|
+
|
|
94
|
+
* Integrate Rails configurations (e.g. database) into Settei.
|
|
95
|
+
* Explore deep merge hash so development.yml can combine with default.yml.
|
|
96
|
+
* Make loader configurable so it is easy to add and mix functionality.
|
|
97
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "settei"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/settei.rb
ADDED
data/lib/settei/base.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
|
|
3
|
+
# Accessor for configuration values in a hash.
|
|
4
|
+
module Settei
|
|
5
|
+
class Base
|
|
6
|
+
extend Forwardable
|
|
7
|
+
# @!method dig(key, ...)
|
|
8
|
+
# @see Hash#dig
|
|
9
|
+
# @!method merge(other_hash)
|
|
10
|
+
# @see Hash#merge
|
|
11
|
+
# @!method fetch(key [, default])
|
|
12
|
+
# @see Hash#fetch
|
|
13
|
+
# @!method has_key?(key)
|
|
14
|
+
# @see Hash#has_key?
|
|
15
|
+
# @!method include?(key)
|
|
16
|
+
# @see Hash#include?
|
|
17
|
+
# @!method key?(key)
|
|
18
|
+
# @see Hash#key?
|
|
19
|
+
# @!method member?(key)
|
|
20
|
+
# @see Hash#member?
|
|
21
|
+
# @!method to_hash
|
|
22
|
+
# @!method to_h
|
|
23
|
+
def_delegators :@config, :dig, :merge!, :fetch, :has_key?, :include?, :key?, :member?, :to_hash, :to_h
|
|
24
|
+
|
|
25
|
+
# @param config [Hash] configuration
|
|
26
|
+
def initialize(config)
|
|
27
|
+
if !config.is_a? Hash
|
|
28
|
+
raise ArgumentError.new('config is not a hash')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
self.config = config
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Same as {#dig}, but will wrap return value as a {Settei::Base} if it is a hash.
|
|
35
|
+
def dig_and_wrap(*args)
|
|
36
|
+
result = dig(*args)
|
|
37
|
+
if result.is_a?(Hash)
|
|
38
|
+
self.class.new(result)
|
|
39
|
+
else
|
|
40
|
+
result
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def merge(*args)
|
|
45
|
+
new_hash = @config.merge(*args)
|
|
46
|
+
self.class.new(new_hash)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def config=(config)
|
|
52
|
+
@config = config
|
|
53
|
+
|
|
54
|
+
begin
|
|
55
|
+
require "active_support/core_ext/hash/indifferent_access"
|
|
56
|
+
@config = @config.with_indifferent_access
|
|
57
|
+
rescue LoadError
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Settei
|
|
2
|
+
module Extensions
|
|
3
|
+
# For computing the a string for host settings. There can be multiple host settings such as asset host.
|
|
4
|
+
module HostUrl
|
|
5
|
+
# @param [String, Symbol] server name of host
|
|
6
|
+
# @param [Hash] params segment key-values to override default. A false value can hide that segment.
|
|
7
|
+
# @option params [String, false] :protocol
|
|
8
|
+
# @option params [String, false] :subdomain
|
|
9
|
+
# @option params [String, false] :domain
|
|
10
|
+
# @option params [Integer, false] :port
|
|
11
|
+
# @return [String] host domain
|
|
12
|
+
def host(server = :default, params = {})
|
|
13
|
+
default_params = dig(:hosts, server)
|
|
14
|
+
params = default_params.merge(params)
|
|
15
|
+
|
|
16
|
+
url = ''
|
|
17
|
+
url << params[:protocol].clone << '://' if params[:protocol]
|
|
18
|
+
url << params[:subdomain].clone << '.' if params[:subdomain]
|
|
19
|
+
url << params[:domain]
|
|
20
|
+
url << ':' << params[:port].to_s if params[:port]
|
|
21
|
+
url
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
module Settei
|
|
2
|
+
module Generators
|
|
3
|
+
class Rails
|
|
4
|
+
def initialize(app_path:)
|
|
5
|
+
@app_path = app_path
|
|
6
|
+
|
|
7
|
+
spec = Gem::Specification.find_by_name("settei")
|
|
8
|
+
@gem_path = spec.gem_dir
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def run
|
|
12
|
+
create_setting_rb
|
|
13
|
+
create_ymls
|
|
14
|
+
update_application_rb
|
|
15
|
+
update_gitignore
|
|
16
|
+
update_deploy_rb
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def create_setting_rb
|
|
22
|
+
file_name = 'config/setting.rb'.freeze
|
|
23
|
+
|
|
24
|
+
create_if_absent(file_name) do |file_name|
|
|
25
|
+
FileUtils.cp(
|
|
26
|
+
File.join(@gem_path, 'templates/setting.rb'),
|
|
27
|
+
File.join(@app_path, file_name)
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def create_ymls
|
|
33
|
+
[:production, :default].each do |env|
|
|
34
|
+
file_name = "config/environments/#{env}.yml"
|
|
35
|
+
|
|
36
|
+
create_if_absent(file_name) do |file_name|
|
|
37
|
+
FileUtils.cp(
|
|
38
|
+
File.join(@gem_path, 'templates/setting.yml'),
|
|
39
|
+
File.join(@app_path, file_name)
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def update_application_rb
|
|
46
|
+
file_name = 'config/application.rb'
|
|
47
|
+
file_path = File.join(@app_path, file_name)
|
|
48
|
+
text = "require_relative 'setting'"
|
|
49
|
+
|
|
50
|
+
file_content = File.read(file_path)
|
|
51
|
+
return if file_content.include?(text)
|
|
52
|
+
|
|
53
|
+
gsub_file(file_name, file_path, "require 'rails/all'", "require 'rails/all'\n\n#{text}")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def update_gitignore
|
|
57
|
+
file_name = '.gitignore'
|
|
58
|
+
file_path = File.join(@app_path, file_name)
|
|
59
|
+
text = "\n/config/environments/*.yml"
|
|
60
|
+
|
|
61
|
+
append(file_name, file_path, text)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def update_deploy_rb
|
|
65
|
+
file_name = 'config/deploy.rb'
|
|
66
|
+
file_path = File.join(@app_path, file_name)
|
|
67
|
+
|
|
68
|
+
return if !File.exist?(file_path)
|
|
69
|
+
|
|
70
|
+
file_content = File.read(file_path)
|
|
71
|
+
return if file_content.include?('Settei::')
|
|
72
|
+
|
|
73
|
+
if defined?(Mina)
|
|
74
|
+
text = File.read(File.join(@gem_path, 'templates/_mina.rb'))
|
|
75
|
+
elsif defined?(Capistrano)
|
|
76
|
+
text = File.read(File.join(@gem_path, 'templates/_capistrano.rb'))
|
|
77
|
+
else
|
|
78
|
+
return
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
text.prepend("\n\n# Settei: append serialized config as an environment variable\n")
|
|
82
|
+
|
|
83
|
+
append(file_name, file_path, text)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def append(file_name, file_path, text)
|
|
87
|
+
file_content = File.read(file_path)
|
|
88
|
+
if !file_content.include?(text)
|
|
89
|
+
File.open(file_path, 'a+') { |file| file.write(text) }
|
|
90
|
+
puts "Appended: #{file_name}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def create_if_absent(file_name)
|
|
95
|
+
if File.exist?(file_name)
|
|
96
|
+
puts "Already exists: #{file_name}, skipped"
|
|
97
|
+
else
|
|
98
|
+
yield file_name
|
|
99
|
+
puts "Created: #{file_name}"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Copied and modified from thor
|
|
104
|
+
def gsub_file(file_name, file_path, flag, *args, &block)
|
|
105
|
+
content = File.read(file_path)
|
|
106
|
+
content.gsub!(flag, *args, &block)
|
|
107
|
+
File.open(file_path, "wb") { |file| file.write(content) }
|
|
108
|
+
|
|
109
|
+
puts "Inserted: #{file_name}"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'zlib'
|
|
4
|
+
|
|
5
|
+
module Settei
|
|
6
|
+
module Loaders
|
|
7
|
+
# Loader designed to load hash from environment variable and YAML files.
|
|
8
|
+
# After initialization, call {#load} to load hash into memory,
|
|
9
|
+
# then call {#as_hash}, {#as_env_value}, or {#as_env_assignment} to obtain the results.
|
|
10
|
+
# e.g. `loader.load(:production).as_hash`
|
|
11
|
+
class SimpleLoader
|
|
12
|
+
attr_reader :env_name
|
|
13
|
+
|
|
14
|
+
# @param dir [String] path of directory containing config YAML files
|
|
15
|
+
# @param env_name [String] name for environment variable
|
|
16
|
+
def initialize(dir: nil, env_name: 'APP_CONFIG')
|
|
17
|
+
@dir = dir
|
|
18
|
+
@env_name = env_name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Loads yaml file into memory.
|
|
22
|
+
# If `ENV[@env_name]` exists, loader loads from it,
|
|
23
|
+
# otherwise load from YAML file.
|
|
24
|
+
#
|
|
25
|
+
# YAML file is picked based on provided `environment`.
|
|
26
|
+
# If environment is not specified,
|
|
27
|
+
# or specified environment file does not exist,
|
|
28
|
+
# default.yml is loaded.
|
|
29
|
+
#
|
|
30
|
+
# @param environment [String] application environment (e.g. production/test)
|
|
31
|
+
# @return [self] for further chaining
|
|
32
|
+
def load(environment = nil)
|
|
33
|
+
if !ENV[@env_name].nil?
|
|
34
|
+
@yaml = Zlib::Inflate.inflate(
|
|
35
|
+
Base64.strict_decode64(ENV[@env_name])
|
|
36
|
+
)
|
|
37
|
+
else
|
|
38
|
+
if environment
|
|
39
|
+
env_specific_file_path = "#{@dir}/#{environment}.yml"
|
|
40
|
+
if File.exist?(env_specific_file_path)
|
|
41
|
+
file_path = env_specific_file_path
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
file_path ||= "#{@dir}/default.yml"
|
|
45
|
+
|
|
46
|
+
@yaml = open(file_path).read
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
self
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @return [Hash]
|
|
53
|
+
def as_hash
|
|
54
|
+
ensure_loaded!
|
|
55
|
+
|
|
56
|
+
YAML.load(@yaml)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [String] serialized config hash, for passing as environment variable
|
|
60
|
+
def as_env_value
|
|
61
|
+
ensure_loaded!
|
|
62
|
+
|
|
63
|
+
Base64.strict_encode64(
|
|
64
|
+
Zlib::Deflate.deflate(@yaml)
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Convenience method for outputting "NAME=VALUE" in one call.
|
|
69
|
+
# @return [String] {#as_env_value} with assignment to `env_name`
|
|
70
|
+
def as_env_assignment
|
|
71
|
+
ensure_loaded!
|
|
72
|
+
|
|
73
|
+
"#{@env_name}=#{as_env_value}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def ensure_loaded!
|
|
79
|
+
if !@yaml
|
|
80
|
+
raise 'Call `load` first to load YAML into memory.'
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/settei.gemspec
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require "settei/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "settei"
|
|
7
|
+
spec.version = Settei::VERSION
|
|
8
|
+
spec.authors = ["lulalala"]
|
|
9
|
+
spec.email = ["mark@goodlife.tw"]
|
|
10
|
+
|
|
11
|
+
spec.summary = %q{Ruby configuration}
|
|
12
|
+
#spec.description = %q{TODO: Write a longer description or delete this line.}
|
|
13
|
+
spec.homepage = "https://github.com/lulalala/settei"
|
|
14
|
+
spec.licenses = ['MIT']
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
|
18
|
+
end
|
|
19
|
+
spec.bindir = "exe"
|
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
21
|
+
spec.require_paths = ["lib"]
|
|
22
|
+
|
|
23
|
+
spec.required_ruby_version = '>= 2.3.0'
|
|
24
|
+
|
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.7.0"
|
|
28
|
+
spec.add_development_dependency "rails"
|
|
29
|
+
end
|
data/templates/_mina.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
require 'settei/loaders/simple_loader'
|
|
2
|
+
loader = Settei::Loaders::SimpleLoader.new(
|
|
3
|
+
dir: File.join(File.dirname(__FILE__), "environments")
|
|
4
|
+
)
|
|
5
|
+
loader.load(fetch(:rails_env))
|
|
6
|
+
|
|
7
|
+
set :bundle_prefix, -> {
|
|
8
|
+
%{#{loader.as_env_assignment} RAILS_ENV="#{fetch(:rails_env)}" #{fetch(:bundle_bin)} exec}
|
|
9
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'settei/loaders/simple_loader'
|
|
2
|
+
require 'settei/base'
|
|
3
|
+
require 'settei/extensions/host_url'
|
|
4
|
+
|
|
5
|
+
if defined? Rails
|
|
6
|
+
rails_env = Rails.env
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
loader= Settei::Loaders::SimpleLoader.new(
|
|
10
|
+
dir: File.join(File.dirname(__FILE__), "environments")
|
|
11
|
+
)
|
|
12
|
+
Setting = Settei::Base.new(loader.load(rails_env).as_hash)
|
|
13
|
+
Setting.extend Settei::Extensions::HostUrl
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
the_answer_to_life_the_universe_and_everything: 42
|
metadata
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: settei
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- lulalala
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2018-03-06 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.16'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.16'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rspec
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 3.7.0
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 3.7.0
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rails
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
description:
|
|
70
|
+
email:
|
|
71
|
+
- mark@goodlife.tw
|
|
72
|
+
executables: []
|
|
73
|
+
extensions: []
|
|
74
|
+
extra_rdoc_files: []
|
|
75
|
+
files:
|
|
76
|
+
- ".gitignore"
|
|
77
|
+
- ".rspec"
|
|
78
|
+
- ".yardopts"
|
|
79
|
+
- Gemfile
|
|
80
|
+
- Gemfile.lock
|
|
81
|
+
- README.md
|
|
82
|
+
- Rakefile
|
|
83
|
+
- bin/console
|
|
84
|
+
- bin/setup
|
|
85
|
+
- lib/settei.rb
|
|
86
|
+
- lib/settei/base.rb
|
|
87
|
+
- lib/settei/extensions/host_url.rb
|
|
88
|
+
- lib/settei/generators/rails.rb
|
|
89
|
+
- lib/settei/loaders/simple_loader.rb
|
|
90
|
+
- lib/settei/railtie.rb
|
|
91
|
+
- lib/settei/version.rb
|
|
92
|
+
- lib/tasks/settei_tasks.rake
|
|
93
|
+
- settei.gemspec
|
|
94
|
+
- templates/_capistrano.rb
|
|
95
|
+
- templates/_mina.rb
|
|
96
|
+
- templates/setting.rb
|
|
97
|
+
- templates/setting.yml
|
|
98
|
+
homepage: https://github.com/lulalala/settei
|
|
99
|
+
licenses:
|
|
100
|
+
- MIT
|
|
101
|
+
metadata: {}
|
|
102
|
+
post_install_message:
|
|
103
|
+
rdoc_options: []
|
|
104
|
+
require_paths:
|
|
105
|
+
- lib
|
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: 2.3.0
|
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
|
+
requirements:
|
|
113
|
+
- - ">="
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: '0'
|
|
116
|
+
requirements: []
|
|
117
|
+
rubyforge_project:
|
|
118
|
+
rubygems_version: 2.6.13
|
|
119
|
+
signing_key:
|
|
120
|
+
specification_version: 4
|
|
121
|
+
summary: Ruby configuration
|
|
122
|
+
test_files: []
|