kamaze-project 1.0.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.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +18 -0
  3. data/bin/plop +5 -0
  4. data/lib/kamaze-project.rb +39 -0
  5. data/lib/kamaze/project.rb +155 -0
  6. data/lib/kamaze/project/boot/core_ext.rb +16 -0
  7. data/lib/kamaze/project/boot/listen.rb +38 -0
  8. data/lib/kamaze/project/concern.rb +13 -0
  9. data/lib/kamaze/project/concern/cli.rb +53 -0
  10. data/lib/kamaze/project/concern/cli/with_exit_on_failure.rb +36 -0
  11. data/lib/kamaze/project/concern/env.rb +63 -0
  12. data/lib/kamaze/project/concern/helper.rb +20 -0
  13. data/lib/kamaze/project/concern/mode.rb +19 -0
  14. data/lib/kamaze/project/concern/observable.rb +132 -0
  15. data/lib/kamaze/project/concern/sh.rb +91 -0
  16. data/lib/kamaze/project/concern/tasks.rb +55 -0
  17. data/lib/kamaze/project/concern/tools.rb +27 -0
  18. data/lib/kamaze/project/config.rb +58 -0
  19. data/lib/kamaze/project/core_ext/object.rb +27 -0
  20. data/lib/kamaze/project/core_ext/pp.rb +28 -0
  21. data/lib/kamaze/project/debug.rb +136 -0
  22. data/lib/kamaze/project/dsl.rb +16 -0
  23. data/lib/kamaze/project/dsl/definition.rb +43 -0
  24. data/lib/kamaze/project/dsl/setup.rb +11 -0
  25. data/lib/kamaze/project/helper.rb +63 -0
  26. data/lib/kamaze/project/helper/inflector.rb +44 -0
  27. data/lib/kamaze/project/helper/project.rb +34 -0
  28. data/lib/kamaze/project/helper/project/config.rb +25 -0
  29. data/lib/kamaze/project/observable.rb +20 -0
  30. data/lib/kamaze/project/observer.rb +37 -0
  31. data/lib/kamaze/project/resources/Vagrantfile +128 -0
  32. data/lib/kamaze/project/resources/config/tools.yml +15 -0
  33. data/lib/kamaze/project/struct.rb +34 -0
  34. data/lib/kamaze/project/tasks/cs.rb +23 -0
  35. data/lib/kamaze/project/tasks/cs/control.rb +17 -0
  36. data/lib/kamaze/project/tasks/cs/correct.rb +17 -0
  37. data/lib/kamaze/project/tasks/cs/pre_commit.rb +66 -0
  38. data/lib/kamaze/project/tasks/doc.rb +21 -0
  39. data/lib/kamaze/project/tasks/doc/watch.rb +41 -0
  40. data/lib/kamaze/project/tasks/gem.rb +14 -0
  41. data/lib/kamaze/project/tasks/gem/build.rb +34 -0
  42. data/lib/kamaze/project/tasks/gem/compile.rb +30 -0
  43. data/lib/kamaze/project/tasks/gem/gemspec.rb +20 -0
  44. data/lib/kamaze/project/tasks/gem/install.rb +32 -0
  45. data/lib/kamaze/project/tasks/gem/push.rb +27 -0
  46. data/lib/kamaze/project/tasks/misc/gitignore.rb +29 -0
  47. data/lib/kamaze/project/tasks/shell.rb +17 -0
  48. data/lib/kamaze/project/tasks/sources.rb +6 -0
  49. data/lib/kamaze/project/tasks/sources/license.rb +35 -0
  50. data/lib/kamaze/project/tasks/test.rb +16 -0
  51. data/lib/kamaze/project/tasks/vagrant.rb +71 -0
  52. data/lib/kamaze/project/tasks/version/edit.rb +16 -0
  53. data/lib/kamaze/project/tools.rb +18 -0
  54. data/lib/kamaze/project/tools/base_tool.rb +55 -0
  55. data/lib/kamaze/project/tools/console.rb +48 -0
  56. data/lib/kamaze/project/tools/console/output.rb +120 -0
  57. data/lib/kamaze/project/tools/console/output/buffer.rb +48 -0
  58. data/lib/kamaze/project/tools/gemspec.rb +33 -0
  59. data/lib/kamaze/project/tools/gemspec/builder.rb +99 -0
  60. data/lib/kamaze/project/tools/gemspec/concern.rb +13 -0
  61. data/lib/kamaze/project/tools/gemspec/concern/reading.rb +49 -0
  62. data/lib/kamaze/project/tools/gemspec/packager.rb +67 -0
  63. data/lib/kamaze/project/tools/gemspec/packer.rb +89 -0
  64. data/lib/kamaze/project/tools/gemspec/packer/command.rb +143 -0
  65. data/lib/kamaze/project/tools/gemspec/reader.rb +70 -0
  66. data/lib/kamaze/project/tools/gemspec/reader/decorator.rb +78 -0
  67. data/lib/kamaze/project/tools/gemspec/writer.rb +127 -0
  68. data/lib/kamaze/project/tools/gemspec/writer/dep_gen.rb +61 -0
  69. data/lib/kamaze/project/tools/gemspec/writer/dependency.rb +104 -0
  70. data/lib/kamaze/project/tools/git.rb +95 -0
  71. data/lib/kamaze/project/tools/git/hooks.rb +66 -0
  72. data/lib/kamaze/project/tools/git/hooks/base_hook.rb +33 -0
  73. data/lib/kamaze/project/tools/git/hooks/pre_commit.rb +81 -0
  74. data/lib/kamaze/project/tools/git/status.rb +101 -0
  75. data/lib/kamaze/project/tools/git/status/decorator.rb +39 -0
  76. data/lib/kamaze/project/tools/git/status/file.rb +180 -0
  77. data/lib/kamaze/project/tools/git/status/files_array.rb +39 -0
  78. data/lib/kamaze/project/tools/git/status/index.rb +77 -0
  79. data/lib/kamaze/project/tools/git/status/worktree.rb +19 -0
  80. data/lib/kamaze/project/tools/git/util.rb +35 -0
  81. data/lib/kamaze/project/tools/licenser.rb +197 -0
  82. data/lib/kamaze/project/tools/packager.rb +86 -0
  83. data/lib/kamaze/project/tools/packager/filesystem.rb +178 -0
  84. data/lib/kamaze/project/tools/packager/filesystem/operator.rb +83 -0
  85. data/lib/kamaze/project/tools/packager/filesystem/operator/utils.rb +77 -0
  86. data/lib/kamaze/project/tools/process_locker.rb +106 -0
  87. data/lib/kamaze/project/tools/rspec.rb +115 -0
  88. data/lib/kamaze/project/tools/rubocop.rb +128 -0
  89. data/lib/kamaze/project/tools/rubocop/arguments.rb +19 -0
  90. data/lib/kamaze/project/tools/rubocop/config.rb +43 -0
  91. data/lib/kamaze/project/tools/shell.rb +85 -0
  92. data/lib/kamaze/project/tools/vagrant.rb +182 -0
  93. data/lib/kamaze/project/tools/vagrant/composer.rb +88 -0
  94. data/lib/kamaze/project/tools/vagrant/composer/file.rb +79 -0
  95. data/lib/kamaze/project/tools/vagrant/remote.rb +79 -0
  96. data/lib/kamaze/project/tools/vagrant/shell.rb +102 -0
  97. data/lib/kamaze/project/tools/vagrant/writer.rb +81 -0
  98. data/lib/kamaze/project/tools/yardoc.rb +75 -0
  99. data/lib/kamaze/project/tools/yardoc/file.rb +55 -0
  100. data/lib/kamaze/project/tools/yardoc/watchable.rb +70 -0
  101. data/lib/kamaze/project/tools/yardoc/watcher.rb +106 -0
  102. data/lib/kamaze/project/tools_provider.rb +161 -0
  103. data/lib/kamaze/project/tools_provider/resolver.rb +42 -0
  104. data/lib/kamaze/project/version.rb +104 -0
  105. data/lib/kamaze/project/version.yml +17 -0
  106. metadata +321 -0
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2018 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../yardoc'
10
+ require 'pathname'
11
+
12
+ # Describe a "file"
13
+ #
14
+ # as seen from ``YARD::CLI::Yardoc#files`` and
15
+ # ``YARD::CLI::YardocOptions#files``, as result a file can be evaluating
16
+ # as a glob expression, else file (``filepath``) is a fixed string.
17
+ # Thus, file is castable to ``Array``.
18
+ class Kamaze::Project::Tools::Yardoc::File
19
+ # @param [String] filepath
20
+ # @param [Boolean] glob
21
+ def initialize(filepath, glob = false)
22
+ @glob = !!glob
23
+ @filepath = filepath.to_s
24
+ end
25
+
26
+ # @return [Array<Pathname>]
27
+ def paths
28
+ proc do
29
+ if glob?
30
+ Dir.glob(filepath).map { |f| ::Pathname.new(f).dirname }
31
+ else
32
+ [::Pathname.new(filepath).dirname]
33
+ end
34
+ end.call.uniq.sort.map do |f|
35
+ ::Pathname.new(f.to_s.gsub('./', ''))
36
+ end
37
+ end
38
+
39
+ # Denote file MUST be evaluated as a glob expression
40
+ #
41
+ # @return [Boolean]
42
+ def glob?
43
+ @glob
44
+ end
45
+
46
+ def to_s
47
+ filepath
48
+ end
49
+
50
+ alias to_a paths
51
+
52
+ protected
53
+
54
+ attr_reader :filepath
55
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2018 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../yardoc'
10
+
11
+ # rubocop:disable Style/Documentation
12
+
13
+ class Kamaze::Project::Tools::Yardoc
14
+ module Watchable
15
+ class File < Kamaze::Project::Tools::Yardoc::File
16
+ end
17
+
18
+ private_constant :File
19
+ end
20
+ end
21
+
22
+ # rubocop:enable Style/Documentation
23
+
24
+ # Provide watch related methods
25
+ #
26
+ # Yardoc (wrapper class) is used by a Watcher using tools
27
+ # it MUST provide some methods used to:
28
+ #
29
+ # * initialize ``Listen``
30
+ # * provide patterns (glob pattern matching)
31
+ #
32
+ # Instance of ``YARD::CLI::Yardoc`` is retrieved through ``core`` method
33
+ module Kamaze::Project::Tools::Yardoc::Watchable
34
+ # Get paths
35
+ #
36
+ # @return [Array<Pathname>]
37
+ def paths
38
+ files.map do |file|
39
+ file.to_a.sort[0]
40
+ end.flatten.compact.uniq.sort
41
+ end
42
+
43
+ # Get patterns (usable for glob pattern matching)
44
+ #
45
+ # @return [Array<String>]
46
+ def patterns
47
+ files.map(&:to_s)
48
+ end
49
+
50
+ # Get files
51
+ #
52
+ # Mostly patterns,
53
+ # addition of ``files`` with ``options.files``
54
+ # SHOULD include ``README`` file, when ``.yardopts`` defined
55
+ #
56
+ # @return [Array<Kamaze::Project::Tools::Yardoc::File>]
57
+ def files
58
+ [
59
+ core.files.to_a.flatten.map { |f| File.new(f, true) },
60
+ core.options.files.to_a.map { |f| File.new(f.filename, false) }
61
+ ].flatten
62
+ end
63
+
64
+ # Ignores files matching path match (regexp)
65
+ #
66
+ # @return [Array<String>]
67
+ def excluded
68
+ core.excluded
69
+ end
70
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2018 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../yardoc'
10
+
11
+ class Kamaze::Project::Tools::Yardoc
12
+ class Watcher < Kamaze::Project::Tools::BaseTool
13
+ end
14
+ end
15
+
16
+ # Provide a watcher built on top of Yardoc
17
+ class Kamaze::Project::Tools::Yardoc::Watcher
18
+ # @type [Array<String>]
19
+ attr_writer :paths
20
+
21
+ # @type [Hash]
22
+ attr_accessor :options
23
+
24
+ # @type [Array<String>]
25
+ attr_writer :patterns
26
+
27
+ # Watch for changes
28
+ #
29
+ # Non-blocking, unless ``wait``
30
+ #
31
+ # @param [Boolean] wait
32
+ # @return [self]
33
+ def watch(wait = false)
34
+ listener = ::Listen.to(*paths, options) do |mod, add, rem|
35
+ if trigger?(mod + add + rem)
36
+ yardoc.run
37
+ end
38
+ end
39
+
40
+ listener.start
41
+ sleep if wait
42
+
43
+ self
44
+ end
45
+
46
+ # @return [Array<String>]
47
+ def patterns
48
+ @patterns.map { |pattern| pattern.gsub(%r{^./+}, '') }
49
+ end
50
+
51
+ # @return [Array<String>]
52
+ def paths
53
+ paths = @paths.map(&:to_s)
54
+
55
+ paths.include?('.') ? ['.'] : paths
56
+ end
57
+
58
+ def mutable_attributes
59
+ [:paths, :options, :patterns]
60
+ end
61
+
62
+ protected
63
+
64
+ # Transform paths to relative paths
65
+ #
66
+ # @param [String|Pathname|Array<String>] paths
67
+ def rel(paths)
68
+ paths = [paths] unless paths.is_a?(Array)
69
+
70
+ paths.map do |path|
71
+ path.to_s.gsub(%r{^#{Dir.pwd}/+}, '')
72
+ end
73
+ end
74
+
75
+ # Denote paths trigger (require) action
76
+ #
77
+ # @param [String|Pathname|Array<String>] paths
78
+ # @return [Boolean]
79
+ def trigger?(paths)
80
+ paths = [paths] unless paths.is_a?(Array)
81
+
82
+ paths.map(&:to_s)
83
+ .map { |path| rel(path)[0] }
84
+ .each do |path|
85
+ patterns.each do |pattern|
86
+ return true if File.fnmatch(pattern, path, File::FNM_PATHNAME)
87
+ end
88
+ end
89
+
90
+ false
91
+ end
92
+
93
+ def setup
94
+ @paths ||= yardoc.paths
95
+ @patterns ||= yardoc.patterns
96
+ @options = {
97
+ only: /\.(rb|md)$/,
98
+ ignore: yardoc.excluded.map { |pattern| /#{pattern}/ }
99
+ }.merge(@options.to_h)
100
+ end
101
+
102
+ # @return [Kamaze::Project::Tools::Yardoc]
103
+ def yardoc
104
+ Kamaze.project.tools.fetch('yardoc')
105
+ end
106
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2018 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../project'
10
+
11
+ class Kamaze::Project
12
+ class ToolsProvider
13
+ class Resolver
14
+ end
15
+ end
16
+ end
17
+
18
+ require_relative 'tools_provider/resolver'
19
+
20
+ # Tools provider
21
+ #
22
+ # Tools are instantiated on demand,
23
+ # each demand generates a fresh new tool instance, avoiding risk
24
+ # to reuse a previous altered version of a tool.
25
+ #
26
+ # Sample of use:
27
+ #
28
+ # ```ruby
29
+ # project.tools.fetch(:licenser).process do |licenser|
30
+ # process.license = project.version.license_header
31
+ # process.patterns = ['bin/*', 'lib/**/**.rb']
32
+ # process.output = STDOUT
33
+ # end
34
+ # ```
35
+ class Kamaze::Project::ToolsProvider
36
+ class << self
37
+ # Default tools
38
+ #
39
+ # Tools default values can be ``Class`` or ``String`` (or ``Symbol``),
40
+ # when value is not a ``Class``, it is resolved using ``inflector``
41
+ #
42
+ # @return [Hash]
43
+ def defaults
44
+ items.freeze
45
+ end
46
+
47
+ protected
48
+
49
+ # Get items
50
+ #
51
+ # Items are collected from a YAML file.
52
+ #
53
+ # @return [Hash]
54
+ def items
55
+ config = "#{__dir__}/resources/config/tools.yml"
56
+ defaults = YAML.load_file(config)
57
+
58
+ Hash[defaults.collect { |k, v| [k.to_sym, v] }]
59
+ end
60
+ end
61
+
62
+ # @param [Hash] items
63
+ def initialize(items = {})
64
+ @items = Hash[self.class.defaults].merge(items)
65
+ @cache = {}
66
+ @resolver = Resolver.new
67
+ end
68
+
69
+ # @param [Hash] items
70
+ # @return [self]
71
+ def merge!(items)
72
+ items = Hash[items.map { |k, v| [k.to_sym, v] }]
73
+ @cache.delete_if { |k| items.member?(k) }
74
+
75
+ @items.merge!(items)
76
+
77
+ self
78
+ end
79
+
80
+ # Associates the value given by value with the given key.
81
+ #
82
+ # @param [String|Symbol] name
83
+ # @param [Class] value
84
+ def []=(name, value)
85
+ merge!(name => value)
86
+ end
87
+
88
+ # Prevents further modifications.
89
+ #
90
+ # See also ``Object#frozen?``.
91
+ #
92
+ # @return [self]
93
+ def freeze
94
+ @items.freeze
95
+ super
96
+ end
97
+
98
+ # Get a fresh instance with given name
99
+ #
100
+ # @param [Symbol|String] name
101
+ # @return [Object]
102
+ # @raise [KeyError]
103
+ def fetch(name)
104
+ raise KeyError, "key not found: :#{name}" unless member?(name)
105
+
106
+ self[name]
107
+ end
108
+
109
+ # Get a fresh instance with given name
110
+ #
111
+ # @param [Symbol|String] name
112
+ # @return [Object|nil]
113
+ def [](name)
114
+ name = name.to_sym
115
+
116
+ return nil unless member?(name)
117
+
118
+ @cache[name] ||= @items.fetch(name).yield_self do |klass|
119
+ resolver.classify(klass)
120
+ end
121
+
122
+ @cache.fetch(name).new
123
+ end
124
+
125
+ alias get fetch
126
+
127
+ # Get all instances at once
128
+ #
129
+ # @return [Hash]
130
+ def to_h
131
+ @items
132
+ .map { |k, v| [k, @cache[k] ||= resolver.classify(v)] }
133
+ .yield_self { |results| Hash[results] }
134
+ .yield_self { |items| Hash[items.collect { |k, v| [k, v.new] }] }
135
+ end
136
+
137
+ # Returns ``true`` if the given key is present
138
+ #
139
+ # @param [Symbol|String] name
140
+ # @return [Boolean]
141
+ def member?(name)
142
+ name = name.to_sym
143
+
144
+ @items.member?(name)
145
+ end
146
+
147
+ protected
148
+
149
+ # @return [Resolver]
150
+ attr_reader :resolver
151
+
152
+ # Base items, before (if needed) resolution.
153
+ #
154
+ # @return [Hash]
155
+ attr_reader :items
156
+
157
+ # Used to avoid classes resolution.
158
+ #
159
+ # @return [Hash]
160
+ attr_reader :cache
161
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2018 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../tools_provider'
10
+ require_relative '../../project/concern/helper'
11
+
12
+ class Kamaze::Project::ToolsProvider
13
+ class Resolver
14
+ end
15
+ end
16
+
17
+ # Provide class name resolution
18
+ class Kamaze::Project::ToolsProvider::Resolver
19
+ include Kamaze::Project::Concern::Helper
20
+
21
+ def initialize
22
+ # @type [Kamaze::Project::Helper::Inflector]
23
+ @inflector = helper.get(:inflector)
24
+ end
25
+
26
+ # Resolve given class path
27
+ #
28
+ # @see Kamaze::Project::Helper::Inflector
29
+ # @param [Symbol|String] klass
30
+ # @return [Class]
31
+ def resolve(klass)
32
+ @inflector.resolve(klass)
33
+ end
34
+
35
+ # Retrieve ``Class`` if necessary with given identifier
36
+ #
37
+ # @param [String|Symbol|Class] klass
38
+ # @return [Class]
39
+ def classify(klass)
40
+ klass.is_a?(Class) ? klass : self.resolve(klass)
41
+ end
42
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2017-2018 Dimitri Arrigoni <dimitri@arrigoni.me>
4
+ # License GPLv3+: GNU GPL version 3 or later
5
+ # <http://www.gnu.org/licenses/gpl.html>.
6
+ # This is free software: you are free to change and redistribute it.
7
+ # There is NO WARRANTY, to the extent permitted by law.
8
+
9
+ require_relative '../project'
10
+
11
+ require 'yaml'
12
+ require 'pathname'
13
+ require 'dry/inflector'
14
+
15
+ # Describe version using a YAML file.
16
+ #
17
+ # @see https://github.com/jcangas/version_info
18
+ class Kamaze::Project::Version
19
+ # Get filepath used to parse version (YAML file).
20
+ #
21
+ # @return [Pathname|String]
22
+ attr_reader :file_name
23
+
24
+ # @param [String] file_name
25
+ def initialize(file_name = self.class.file_name)
26
+ @file_name = file_name.freeze
27
+
28
+ self.load_file
29
+ .map { |k, v| self.attr_set(k, v) }
30
+ .yield_self { |loaded| @data_loaded = loaded.to_h }
31
+ end
32
+
33
+ # Denote version has enough (mninimal) attributes defined.
34
+ #
35
+ # @return [Boolean]
36
+ def valid?
37
+ ![:major, :minor, :patch]
38
+ .map { |method| public_send(method) }
39
+ .map { |v| v.to_s.empty? ? nil : v }
40
+ .include?(nil)
41
+ rescue NameError
42
+ false
43
+ end
44
+
45
+ # @return [String]
46
+ def to_s
47
+ [major, minor, patch].join('.')
48
+ end
49
+
50
+ # @return [Hash]
51
+ def to_h
52
+ data_loaded.clone.freeze
53
+ end
54
+
55
+ # Return the path as a String.
56
+ #
57
+ # @see https://ruby-doc.org/stdlib-2.5.0/libdoc/pathname/rdoc/Pathname.html#method-i-to_path
58
+ # @return [String]
59
+ def to_path
60
+ file_name.to_s
61
+ end
62
+
63
+ class << self
64
+ # Get default filename.
65
+ #
66
+ # @return [Pathname]
67
+ def file_name
68
+ Pathname.new(__dir__).join('version.yml')
69
+ end
70
+ end
71
+
72
+ protected
73
+
74
+ attr_reader :data_loaded
75
+
76
+ # @return [Hash]
77
+ def load_file
78
+ YAML.load_file(file_name).yield_self do |data|
79
+ data == false ? {} : data
80
+ end
81
+ rescue Errno::ENOENT
82
+ {}
83
+ end
84
+
85
+ # Define attribute (as ``ro`` attr) and set value.
86
+ #
87
+ # @param [String|Symbol] attr_name
88
+ # @param [Object] attr_value
89
+ # @return [Array]
90
+ def attr_set(attr_name, attr_value)
91
+ inflector = Dry::Inflector.new
92
+ attr_name = inflector.underscore(attr_name.to_s)
93
+
94
+ self.singleton_class.class_eval do
95
+ attr_accessor attr_name
96
+
97
+ protected "#{attr_name}="
98
+ end
99
+
100
+ self.__send__("#{attr_name}=", attr_value.freeze)
101
+
102
+ [attr_name, attr_value.freeze].freeze
103
+ end
104
+ end