angular_config 0.3.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.
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format doc
2
+ --color
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.2.0
6
+ install: bundle install
7
+ script: bundle exec rake test
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in angular_config.gemspec
4
+ gemspec
@@ -0,0 +1,87 @@
1
+ # AngularConfig
2
+ [![Build Status](https://travis-ci.org/cultuurnet/angular-config.png)](https://travis-ci.org/cultuurnet/angular-config)
3
+
4
+ This tool allows you to inject a JSON configuration into a minified Angular application. It inserts checksummed versions of the
5
+ configuration keys as values during the build process, and provides a mechanism to exchange these keys with the actual values when deploying.
6
+
7
+ This is a hackish solution, but it allows swapping configuration values without having to rebuild the application and does not require changes
8
+ to existing angular code.
9
+ If you are able to change the angular code, a solution like deferred bootstrapping is probably better suited.
10
+
11
+ I created it because, in continuous delivery fashion, I needed to be able to build an application artifact once and deploy it to a number of
12
+ different environments, with only the configuration changing. As minified Angular applications typically embed the configuration in the javascript,
13
+ this is what I came up with.
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'angular_config'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ $ bundle
26
+
27
+ Or install it yourself as:
28
+
29
+ $ gem install angular_config
30
+
31
+ ## Usage
32
+
33
+ ### Commandline tool
34
+
35
+ Create a hashed version of the config.json first:
36
+
37
+ $ angular_config hash -c config.json -t md5 > hashed_config.json
38
+
39
+ Now build the angular app using the hashed configuration file.
40
+
41
+ After that, exchange the config values for the real ones:
42
+
43
+ $ angular_config resolve -t md5 -c config_production.json -f scripts.js
44
+
45
+ If you use cache busting (embedding the md5 hash of the file source in the filename and
46
+ referencing that from the index.html), you will need the calculate a new md5 sum for the
47
+ changed file, rename and reference accordingly.
48
+
49
+ ### Programmatically
50
+
51
+ Create a hashed version of the config.json first:
52
+
53
+ ```
54
+ require 'angular_config'
55
+
56
+ config = AngularConfig::Config.load('config.json', 'md5')
57
+ puts config.hash_values.content.to_json
58
+ ```
59
+
60
+ Now build the angular app using the hashed configuration file.
61
+
62
+ After that, exchange the config values for the real ones:
63
+
64
+ ```
65
+ require 'angular_config'
66
+
67
+ config_hashed_keys = AngularConfig::Config.load('config.json', 'md5').hash_keys
68
+ file = AngularConfig::Source.load('source.js')
69
+
70
+ puts file.resolve(config_hashed_keys).content
71
+ ```
72
+
73
+ If you use cache busting (embedding the md5 hash of the file source in the filename and
74
+ referencing that from the index.html), you will need the calculate a new md5 sum for the
75
+ changed file, rename and reference accordingly.
76
+
77
+ ## Development
78
+
79
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
80
+
81
+ ## Contributing
82
+
83
+ 1. Fork it ( https://github.com/cultuurnet/angular_config/fork )
84
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
85
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
86
+ 4. Push to the branch (`git push origin my-new-feature`)
87
+ 5. Create a new Pull Request
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:test) do |t|
5
+ t.pattern = Dir.glob('spec/**/*_spec.rb')
6
+ t.rspec_opts = '--format documentation'
7
+ end
8
+
9
+ desc "Default task prints the available targets."
10
+ task :default do
11
+ system("rake -T")
12
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'angular_config/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "angular_config"
9
+ spec.version = AngularConfig::VERSION
10
+ spec.authors = ["Kristof Willaert"]
11
+ spec.email = ["kristof.willaert@cultuurnet.be"]
12
+
13
+ spec.summary = %q{Manage configuration in minified/uglified Angular apps}
14
+ spec.description = %q{Manage configuration in minified/uglified Angular apps by swapping out cryptographically hashed values}
15
+ spec.homepage = "https://github.com/cultuurnet/angular_config"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "bin"
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.4"
25
+ spec.add_development_dependency "fakefs", "~> 0.10"
26
+ end
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'angular_config'
5
+
6
+ options = {:type => 'SHA256'}
7
+
8
+ angular_config = OptionParser.new do |ac|
9
+ ac.banner = "Usage: angular_config COMMAND [OPTIONS]"
10
+ ac.separator ""
11
+ ac.separator "Commands"
12
+ ac.separator " hash: convert values of a JSON hash to hashed representations of the keys"
13
+ ac.separator " resolve: resolve hashed keys in a file with actual values"
14
+ ac.separator ""
15
+ ac.separator "Options"
16
+
17
+ ac.on("-c","--config CONFIG","Configuration file containing source JSON hash") do |config|
18
+ options[:source_config] = config
19
+ end
20
+
21
+ ac.on("-f","--file FILE","File to resolve") do |file|
22
+ options[:file] = file
23
+ end
24
+
25
+ ac.on("-t","--type TYPE","Checksum type to use") do |type|
26
+ options[:type] = type
27
+ end
28
+
29
+ ac.on("-h","--help","help") do
30
+ puts angular_config
31
+ end
32
+ end
33
+
34
+ angular_config.parse!
35
+
36
+ case ARGV[0]
37
+ when "hash"
38
+ unless options[:source_config].nil?
39
+ source_config = AngularConfig::Config.load(options[:source_config], options[:type])
40
+ puts source_config.hash_values.content.to_json
41
+ else
42
+ puts angular_config
43
+ end
44
+ when "resolve"
45
+ unless options[:source_config].nil? or options[:file].nil?
46
+ config_hashed_keys = AngularConfig::Config.load(options[:source_config], options[:type]).hash_keys
47
+ file = AngularConfig::Source.load(options[:file])
48
+
49
+ puts file.resolve(config_hashed_keys).content
50
+ else
51
+ puts angular_config
52
+ end
53
+ else
54
+ puts angular_config
55
+ end
@@ -0,0 +1,5 @@
1
+ require 'json'
2
+ require 'digest'
3
+ require 'angular_config/file'
4
+ require 'angular_config/config'
5
+ require 'angular_config/source'
@@ -0,0 +1,44 @@
1
+ module AngularConfig
2
+ class Config
3
+ attr_reader :content
4
+ attr_reader :checksum_type
5
+
6
+ def initialize(config = {}, type = 'SHA256')
7
+ @content = config
8
+ @checksum_type = type.upcase
9
+ end
10
+
11
+ def hash_keys
12
+ hashed_keys = content.each_with_object({}) do |(key, value), result|
13
+ digest = load_constant("Digest::#{checksum_type}").new
14
+ result[digest.hexdigest(key)] = value
15
+ end
16
+ AngularConfig::Config.new(hashed_keys)
17
+ end
18
+
19
+ def hash_values
20
+ hashed_values = content.each_with_object({}) do |(key, value), result|
21
+ digest = load_constant("Digest::#{checksum_type}").new
22
+ result[key] = digest.hexdigest(key)
23
+ end
24
+ AngularConfig::Config.new(hashed_values)
25
+ end
26
+
27
+ def self.load(path, type = 'SHA256')
28
+ AngularConfig::Config.new(JSON.load(AngularConfig::File.new(path).content), type)
29
+ end
30
+
31
+ def self.save(data, path)
32
+ AngularConfig::File.new(path).content = data.to_json
33
+ end
34
+
35
+ private
36
+
37
+ def load_constant(name)
38
+ parts = name.split('::')
39
+ klass = Module.const_get(parts.shift)
40
+ klass = klass.const_get(parts.shift) until parts.empty?
41
+ klass
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,19 @@
1
+ module AngularConfig
2
+ class File
3
+ attr_reader :path
4
+
5
+ def initialize(source_path)
6
+ @path = ::File.expand_path(source_path)
7
+ end
8
+
9
+ def content
10
+ ::File.read(path).chomp
11
+ end
12
+
13
+ def content=(data)
14
+ ::File.open(path, "w") do |file|
15
+ file.write(data)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ module AngularConfig
2
+ class Source
3
+ attr_reader :content
4
+
5
+ def initialize(content)
6
+ @content = content
7
+ end
8
+
9
+ def md5
10
+ Digest::MD5.hexdigest(content)
11
+ end
12
+
13
+ def resolve(hashed_keys)
14
+ hashed_keys.content.each do |key, value|
15
+ if value.is_a?(String)
16
+ self.content.gsub!(key, value)
17
+ else
18
+ self.content.gsub!("\"#{key}\"", value.to_json)
19
+ end
20
+ end
21
+
22
+ self
23
+ end
24
+
25
+ def self.load(path)
26
+ AngularConfig::Source.new AngularConfig::File.new(path).content
27
+ end
28
+
29
+ def self.save(data, path)
30
+ AngularConfig::File.new(path).content = data
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module AngularConfig
2
+ VERSION = "0.3.0"
3
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: angular_config
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kristof Willaert
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-05-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !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: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '10.0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '10.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '3.4'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ - !ruby/object:Gem::Dependency
63
+ name: fakefs
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '0.10'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '0.10'
78
+ description: Manage configuration in minified/uglified Angular apps by swapping out
79
+ cryptographically hashed values
80
+ email:
81
+ - kristof.willaert@cultuurnet.be
82
+ executables:
83
+ - angular_config
84
+ extensions: []
85
+ extra_rdoc_files: []
86
+ files:
87
+ - .gitignore
88
+ - .rspec
89
+ - .travis.yml
90
+ - Gemfile
91
+ - README.md
92
+ - Rakefile
93
+ - angular_config.gemspec
94
+ - bin/angular_config
95
+ - lib/angular_config.rb
96
+ - lib/angular_config/config.rb
97
+ - lib/angular_config/file.rb
98
+ - lib/angular_config/source.rb
99
+ - lib/angular_config/version.rb
100
+ homepage: https://github.com/cultuurnet/angular_config
101
+ licenses: []
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 1.8.23.2
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: Manage configuration in minified/uglified Angular apps
124
+ test_files: []