tty-config 0.3.1 → 0.5.1

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -1
  3. data/LICENSE.txt +1 -1
  4. data/README.md +305 -153
  5. data/lib/tty/config/dependency_loader.rb +55 -0
  6. data/lib/tty/config/generator.rb +57 -0
  7. data/lib/tty/config/marshaller.rb +66 -0
  8. data/lib/tty/config/marshaller_registry.rb +45 -0
  9. data/lib/tty/config/marshallers/hcl_marshaller.rb +30 -0
  10. data/lib/tty/config/marshallers/ini_marshaller.rb +31 -0
  11. data/lib/tty/config/marshallers/java_props_marshaller.rb +28 -0
  12. data/lib/tty/config/marshallers/json_marshaller.rb +28 -0
  13. data/lib/tty/config/marshallers/toml_marshaller.rb +28 -0
  14. data/lib/tty/config/marshallers/yaml_marshaller.rb +32 -0
  15. data/lib/tty/config/marshallers.rb +35 -0
  16. data/lib/tty/config/version.rb +3 -3
  17. data/lib/tty/config.rb +374 -190
  18. data/lib/tty-config.rb +1 -1
  19. metadata +66 -57
  20. data/Rakefile +0 -8
  21. data/bin/console +0 -14
  22. data/bin/setup +0 -8
  23. data/spec/spec_helper.rb +0 -54
  24. data/spec/unit/alias_setting_spec.rb +0 -72
  25. data/spec/unit/append_spec.rb +0 -26
  26. data/spec/unit/autoload_env_spec.rb +0 -62
  27. data/spec/unit/delete_spec.rb +0 -22
  28. data/spec/unit/exist_spec.rb +0 -24
  29. data/spec/unit/fetch_spec.rb +0 -45
  30. data/spec/unit/generate_spec.rb +0 -70
  31. data/spec/unit/merge_spec.rb +0 -13
  32. data/spec/unit/new_spec.rb +0 -6
  33. data/spec/unit/normalize_hash_spec.rb +0 -21
  34. data/spec/unit/read_spec.rb +0 -109
  35. data/spec/unit/remove_spec.rb +0 -16
  36. data/spec/unit/set_from_env_spec.rb +0 -78
  37. data/spec/unit/set_if_empty_spec.rb +0 -26
  38. data/spec/unit/set_spec.rb +0 -62
  39. data/spec/unit/validate_spec.rb +0 -76
  40. data/spec/unit/write_spec.rb +0 -197
  41. data/tasks/console.rake +0 -11
  42. data/tasks/coverage.rake +0 -11
  43. data/tasks/spec.rake +0 -29
  44. data/tty-config.gemspec +0 -30
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTY
4
+ class Config
5
+ module DependencyLoader
6
+ attr_reader :dep_name
7
+
8
+ # Lazy load a dependency
9
+ #
10
+ # @api public
11
+ def dependency(*dep_names, &block)
12
+ self.dep_name = dep_names
13
+ @block = block
14
+ end
15
+
16
+ # Load dependency before object instatiation
17
+ #
18
+ # @api public
19
+ def new(*)
20
+ load
21
+ super
22
+ end
23
+
24
+ # Try loading depedency
25
+ #
26
+ # @api private
27
+ def load
28
+ return if dep_name.nil?
29
+
30
+ dep_name.empty? ? @block.() : dep_name.each { |dep| require(dep) }
31
+ rescue LoadError, NameError => err
32
+ raise DependencyLoadError, "#{raise_error_message} #{err.message}"
33
+ end
34
+
35
+ def inherited(subclass)
36
+ super
37
+ subclass.send(:dep_name=, dep_name)
38
+ end
39
+
40
+ private
41
+
42
+ def raise_error_message
43
+ if dep_name.empty?
44
+ "One or more dependency are missing."
45
+ elsif dep_name.size == 1
46
+ "The dependency `#{dep_name.join}` is missing."
47
+ else
48
+ "The dependencies `#{dep_name.join(', ')}` are missing."
49
+ end
50
+ end
51
+
52
+ attr_writer :dep_name
53
+ end # DependencyLoader
54
+ end # Config
55
+ end # TTY
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTY
4
+ class Config
5
+ module Generator
6
+ # Generate file content based on the data hash
7
+ #
8
+ # @param [Hash] data
9
+ #
10
+ # @return [String]
11
+ # the file content
12
+ #
13
+ # @api public
14
+ def self.generate(data, separator: "=")
15
+ content = []
16
+ values = {}
17
+ sections = {}
18
+
19
+ data.keys.sort.each do |key|
20
+ val = data[key]
21
+ if val.is_a?(NilClass)
22
+ next
23
+ elsif val.is_a?(Hash) ||
24
+ (val.is_a?(Array) && val.first.is_a?(Hash))
25
+ sections[key] = val
26
+ elsif val.is_a?(Array)
27
+ values[key] = val.join(",")
28
+ else
29
+ values[key] = val
30
+ end
31
+ end
32
+
33
+ # values
34
+ values.each do |key, val|
35
+ content << "#{key} #{separator} #{val}"
36
+ end
37
+ content << "" unless values.empty?
38
+
39
+ # sections
40
+ sections.each do |section, object|
41
+ next if object.empty? # only add section if values present
42
+
43
+ content << "[#{section}]"
44
+ if object.is_a?(Array)
45
+ object = object.reduce({}, :merge!)
46
+ end
47
+ object.each do |key, val|
48
+ val = val.join(",") if val.is_a?(Array)
49
+ content << "#{key} #{separator} #{val}" if val
50
+ end
51
+ content << ""
52
+ end
53
+ content.join("\n")
54
+ end
55
+ end # INIFile
56
+ end # Config
57
+ end # TTY
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "dependency_loader"
4
+
5
+ module TTY
6
+ class Config
7
+ module Marshaller
8
+ # @api private
9
+ def self.included(base)
10
+ super
11
+ # Help marshallers to declare their gem dependency
12
+ base.extend DependencyLoader
13
+ # Help marshallers to declare their extension matching
14
+ base.extend ExtensionsStore
15
+ end
16
+
17
+ module ExtensionsStore
18
+ def ext
19
+ @_ext ||= []
20
+ end
21
+
22
+ # Set a list of extensions
23
+ #
24
+ # @example
25
+ # extenion "ext1", "ext2", "ext3"
26
+ #
27
+ # @api public
28
+ def extension(*extensions)
29
+ if extensions[0].is_a?(Array)
30
+ @_ext = extensions[0]
31
+ else
32
+ @_ext = extensions
33
+ end
34
+ end
35
+
36
+ # Copy extensions to a subclass
37
+ #
38
+ # @param [Object] subclass
39
+ #
40
+ # @api private
41
+ def inherited(subclass)
42
+ super
43
+ subclass.instance_variable_set(:@_ext, @_ext.dup)
44
+ end
45
+ end
46
+
47
+ # Marshal object into a given format
48
+ #
49
+ # @param [Object] _object
50
+ #
51
+ # @api public
52
+ def marshal(_object, _options = {})
53
+ raise NotImplementedError
54
+ end
55
+
56
+ # Unmarshal content into a hash object
57
+ #
58
+ # @param [String] _content
59
+ #
60
+ # @api public
61
+ def unmarshal(_content, _options = {})
62
+ raise NotImplementedError
63
+ end
64
+ end # Marshaller
65
+ end # Config
66
+ end # TTY
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTY
4
+ class Config
5
+ class MarshallerRegistry
6
+ # All registered marshallers
7
+ #
8
+ # @api private
9
+ attr_reader :marshallers
10
+
11
+ # @api private
12
+ def initialize(mappings = {})
13
+ @marshallers = mappings
14
+ end
15
+
16
+ def names
17
+ marshallers.keys
18
+ end
19
+
20
+ def objects
21
+ marshallers.values
22
+ end
23
+
24
+ def exts
25
+ marshallers.values.reduce([]) { |acc, obj| acc + obj.ext }
26
+ end
27
+
28
+ def registered?(name_or_object)
29
+ marshallers.key?(name_or_object) || marshallers.value?(name_or_object)
30
+ end
31
+
32
+ def register(name, object)
33
+ marshallers[name] = object
34
+ end
35
+
36
+ def unregister(name)
37
+ marshallers.delete(name)
38
+ end
39
+
40
+ def [](name)
41
+ marshallers.fetch(name)
42
+ end
43
+ end
44
+ end # Config
45
+ end # TTY
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../marshaller"
4
+
5
+ module TTY
6
+ class Config
7
+ module Marshallers
8
+ # Responsible for marshalling content from and into HCL format
9
+ #
10
+ # @api public
11
+ class HCLMarshaller
12
+ include TTY::Config::Marshaller
13
+
14
+ dependency "rhcl"
15
+
16
+ extension ".hcl"
17
+
18
+ def marshal(object)
19
+ Rhcl.dump(object)
20
+ end
21
+
22
+ def unmarshal(content)
23
+ return {} if content == ""
24
+
25
+ Rhcl.parse(content)
26
+ end
27
+ end # HCLMarshaller
28
+ end # Marshallers
29
+ end # Config
30
+ end # TTY
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../generator"
4
+ require_relative "../marshaller"
5
+
6
+ module TTY
7
+ class Config
8
+ module Marshallers
9
+ # Responsible for marshalling content from and into INI format
10
+ #
11
+ # @api public
12
+ class INIMarshaller
13
+ include TTY::Config::Marshaller
14
+
15
+ dependency "inifile"
16
+
17
+ extension ".ini", ".cnf", ".conf", ".cfg", ".cf"
18
+
19
+ def marshal(object)
20
+ TTY::Config::Generator.generate(object)
21
+ end
22
+
23
+ def unmarshal(content)
24
+ ini = IniFile.new(content: content).to_h
25
+ global = ini.delete("global") { {} }
26
+ ini.merge(global)
27
+ end
28
+ end # INIMarshaller
29
+ end # Marshallers
30
+ end # Config
31
+ end # TTY
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../marshaller"
4
+
5
+ module TTY
6
+ class Config
7
+ module Marshallers
8
+ # Responsible for marshalling content from and into Java properties format
9
+ #
10
+ # @api public
11
+ class JavaPropsMarshaller
12
+ include TTY::Config::Marshaller
13
+
14
+ dependency "java-properties"
15
+
16
+ extension ".properties", ".props", ".prop"
17
+
18
+ def marshal(object)
19
+ JavaProperties.generate(object)
20
+ end
21
+
22
+ def unmarshal(content)
23
+ JavaProperties.parse(content)
24
+ end
25
+ end # JavapropsMarshaller
26
+ end # Marshallers
27
+ end # Config
28
+ end # TTY
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../marshaller"
4
+
5
+ module TTY
6
+ class Config
7
+ module Marshallers
8
+ # Responsible for marshalling content from and into JSON format
9
+ #
10
+ # @api public
11
+ class JSONMarshaller
12
+ include TTY::Config::Marshaller
13
+
14
+ dependency "json"
15
+
16
+ extension ".json"
17
+
18
+ def marshal(object)
19
+ JSON.pretty_generate(object)
20
+ end
21
+
22
+ def unmarshal(content)
23
+ JSON.parse(content)
24
+ end
25
+ end # JSONMarshaller
26
+ end # Marshallers
27
+ end # Config
28
+ end # TTY
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../marshaller"
4
+
5
+ module TTY
6
+ class Config
7
+ module Marshallers
8
+ # Responsible for marshalling content from and into TOML format
9
+ #
10
+ # @api public
11
+ class TOMLMarshaller
12
+ include TTY::Config::Marshaller
13
+
14
+ dependency "toml"
15
+
16
+ extension ".toml"
17
+
18
+ def marshal(data)
19
+ TOML::Generator.new(data).body
20
+ end
21
+
22
+ def unmarshal(content)
23
+ TOML::Parser.new(content).parsed
24
+ end
25
+ end # TOMLMarshaller
26
+ end # Marshallers
27
+ end # Config
28
+ end # TTY
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../marshaller"
4
+
5
+ module TTY
6
+ class Config
7
+ module Marshallers
8
+ # Responsible for marshalling content from and into YAML format
9
+ #
10
+ # @api public
11
+ class YAMLMarshaller
12
+ include TTY::Config::Marshaller
13
+
14
+ dependency "yaml"
15
+
16
+ extension ".yaml", ".yml"
17
+
18
+ def marshal(object)
19
+ YAML.dump(TTY::Config.normalize_hash(object, :to_s))
20
+ end
21
+
22
+ def unmarshal(content)
23
+ if YAML.respond_to?(:safe_load)
24
+ YAML.safe_load(content)
25
+ else
26
+ YAML.load(content)
27
+ end
28
+ end
29
+ end # YAMLMarshaller
30
+ end # Marshallers
31
+ end # Config
32
+ end # TTY
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "marshaller_registry"
4
+
5
+ module TTY
6
+ class Config
7
+ module Marshallers
8
+ NO_EXT = ""
9
+
10
+ def marshaller_registry
11
+ @marshaller_registry ||= MarshallerRegistry.new
12
+ end
13
+
14
+ def marshallers
15
+ marshaller_registry.objects
16
+ end
17
+
18
+ def extensions
19
+ marshaller_registry.exts << NO_EXT
20
+ end
21
+
22
+ def registered_marshaller?(name_or_object)
23
+ marshaller_registry.registered?(name_or_object)
24
+ end
25
+
26
+ def register_marshaller(name, object)
27
+ marshaller_registry.register(name, object)
28
+ end
29
+
30
+ def unregister_marshaller(*names)
31
+ names.map { |name| marshaller_registry.unregister(name) }
32
+ end
33
+ end # Marshallers
34
+ end # Config
35
+ end # TTY
@@ -2,6 +2,6 @@
2
2
 
3
3
  module TTY
4
4
  class Config
5
- VERSION = "0.3.1"
6
- end
7
- end
5
+ VERSION = "0.5.1"
6
+ end # Config
7
+ end # TTY