yaml_normalizer 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d872c2e4bbddcde16c368ddd2279ad2b1a5a6f85
4
- data.tar.gz: 0b2f989dfbc4c0be5250f3afffc8fa654703462f
3
+ metadata.gz: f7181101bce00079a445c20da53ef9c0378f5b77
4
+ data.tar.gz: 401cebab8d8d70ed70845e561078448804590214
5
5
  SHA512:
6
- metadata.gz: ca1c6808fc72ce7354a192ff7addc18d0d5fbf409ca030790da5f096977057785aa174307a89ebca66ad744801556895635118df0e7dbce6d20126f1289b72d2
7
- data.tar.gz: 9a3c8646211ecc2279b99f36688f99540115d57d0cb2dfbb707d026346ba671c0b27499ff1e5a5b5675f2ef0cb4cdec2bfdee10e8e123e61fb4cbd58524fcb9f
6
+ metadata.gz: 34ec7614ce553477f4420d964c59a6efe88315d5b55ccca272087f28a41b7e194e2ecc1fd31cd889a24e1712e3c2d11e9a1b6eae0f7ff8ac68fae48e3f4c0842
7
+ data.tar.gz: d05e84ec8b059c83eb4e86c463a7db4206ffc4ed8372b8caa08928077e6025ff3d702eb4398800132c3f6b0c363b7f8fd71e5257ab47778920f5b80dfbcfc8e8
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YamlNormalizer
4
+ module Ext
5
+ # Extends an instance of Hash to add the method namespaced.
6
+ # The approach of extending Hash instances avoids monkey-patching a Ruby
7
+ # Core class and using refinements.
8
+ module Namespaced
9
+ # Transforms a tree-shaped hash into a plain key-value pair Hash,
10
+ # separating tree levels with a dot. namespaced does not modify the Hash
11
+ # it's called on.
12
+ # @example
13
+ # {a: {b: {c: 1}}, b:{x: 2, y: {ok: true}, z: 4}}.namespaced
14
+ # => {"a.b.c"=>1, "b.x"=>2, "b.y.ok"=>true, "b.z"=>4}
15
+ # @param namespace [Array] the namespace cache for the current namespace,
16
+ # used on recursive tree traversal
17
+ # @param tree [Hash] the accumulator object beeing build while recursive
18
+ # traversing the original tree-like Hash
19
+ def namespaced(namespace = [], tree = {})
20
+ each do |key, value|
21
+ child_ns = namespace.dup << key
22
+ if value.instance_of?(Hash)
23
+ value.extend(Namespaced).namespaced child_ns, tree
24
+ else
25
+ tree[child_ns.join('.')] = value
26
+ end
27
+ end
28
+ tree
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YamlNormalizer
4
+ module Ext
5
+ # Extends an instance of Hash to add the method sort_by_key.
6
+ # The approach of extending Hash instances avoids monkey-patching a Ruby
7
+ # Core class and using refinements.
8
+ module SortByKey
9
+ # Sorts entries alphabetically by key and returns a new Hash
10
+ # sort_by_key does not modify the Hash it's called on.
11
+ # @example
12
+ # hash = { { b: { z: 20, x: 10, y: { b: 1, a: 2 } }, a: nil } }
13
+ # hash.extend(YamlNormalizer::Ext::SortByKey)
14
+ # hash.sort_by_key
15
+ # => {:a=>nil, :b=>{:x=>10, :y=>{:a=>2, :b=>1}, :z=>20}}
16
+ # @param recursive [Boolean] defines if sort_by_key is called on child
17
+ # nodes, defaults to true
18
+ def sort_by_key(recursive = true)
19
+ keys.sort.each_with_object({}) do |key, seed|
20
+ value = seed[key] = fetch(key)
21
+ if recursive && value.instance_of?(Hash)
22
+ seed[key] = value.extend(SortByKey).sort_by_key
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YamlNormalizer
4
+ # Ext holds extensions to external dependencies
5
+ # YamlNormalizer does not extend Ruby Core classes to avoid side effects
6
+ module Ext
7
+ end
8
+ end
9
+
10
+ require 'yaml_normalizer/ext/namespaced'
11
+ require 'yaml_normalizer/ext/sort_by_key'
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YamlNormalizer
4
+ module Helpers
5
+ # This helper holds shared functionality to normalize a YAML string.
6
+ module Normalize
7
+ # Transforms a given YAML string to a normalized format.
8
+ # @example
9
+ # class YamlWriter
10
+ # include YamlNormalizer::Helpers::Normalize
11
+ #
12
+ # def initialize(yaml)
13
+ # @yaml = normalize_yaml(yaml)
14
+ # end
15
+ #
16
+ # def write(file)
17
+ # File.open(file,'w') { |f| f.write(@yaml) }
18
+ # end
19
+ # end
20
+ # @param [String] valid YAML string
21
+ # @return [String] normalized YAML string
22
+ def normalize_yaml(yaml)
23
+ hashes = Psych.parse_stream(yaml).transform
24
+ hashes.each { |hash| hash.extend(Ext::SortByKey) }
25
+ hashes.map(&:sort_by_key).map(&:to_yaml).join
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YamlNormalizer
4
+ # Holds all Yaml Normalizer helpers
5
+ module Helpers
6
+ end
7
+ end
8
+
9
+ require 'yaml_normalizer/helpers/normalize'
@@ -1,30 +1,61 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ lib = File.expand_path(File.join('..', '..', '..', 'lib'), __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'yaml_normalizer'
6
+ require 'rake/tasklib'
4
7
 
5
8
  module YamlNormalizer
6
9
  # Provides Rake task integration
7
10
  class RakeTask < ::Rake::TaskLib
11
+ # The name of the task
8
12
  # @return [String] name of the Rake task
9
13
  attr_accessor :name
10
- # @return [Array] arguments to be passed to Suggest.run
11
- attr_accessor :args
12
14
 
15
+ # The YAML files to process.
16
+ # @example Task files assignment
17
+ # YamlNormalizer::RakeTask.new do |task|
18
+ # task.files = ['config/locale/*.yml', 'config/*.yml']
19
+ # end
20
+ # @return [Array<String>] a list of file globing Strings
21
+ attr_accessor :files
22
+
23
+ # Create a YamlNormalizer rake task object.
24
+ # Use this to
25
+ # @example
26
+ # In your Rakefile, add:
27
+ # YamlNormalizer::RakeTask.new
28
+ #
29
+ # To be more specific, configure YAML Normalizer's mode and files like so:
30
+ # YamlNormalizer::RakeTask.new do |config|
31
+ # config.files = Dir[File.join(File.dirname(__FILE__), 'include.yml')]
32
+ # end
33
+ #
34
+ # This gives you the following tasks (run rake -T)
35
+ # rake yaml:check # Check if given YAML are normalized
36
+ # rake yaml:normalize # Normalize given YAML files
13
37
  # @param name [String] name of the Rake task
14
- # @param *args [Array] arguments to be passed to Normalize.call
15
38
  # @param &block [Proc] optional, evaluated inside the task definition
16
- def initialize(name = 'yaml_normalizer', *args, &block)
17
- @name = name
18
- @args = args
39
+ def initialize(name = 'yaml', &block)
19
40
  yield(self) if block
20
41
 
21
- desc 'Normalize all YAML files in path'
22
- task(@name) { normalize }
42
+ desc 'Check if configured YAML are normalized'
43
+ task("#{name}:check") { check }
44
+
45
+ desc 'Normalize configured YAML files'
46
+ task("#{name}:normalize") { normalize }
47
+ end
48
+
49
+ private
50
+
51
+ # Checks if configured YAML are normalized
52
+ def check
53
+ Services::Check.call(*files)
23
54
  end
24
55
 
25
- # @return [void]
56
+ # Normalizes configured YAML files
26
57
  def normalize
27
- ::YamlNormalizer::Services::Normalize.call('**/*')
58
+ Services::Normalize.call(*files)
28
59
  end
29
60
  end
30
61
  end
@@ -5,14 +5,45 @@ module YamlNormalizer
5
5
  # The Base Service provides a convenience class method "call" to initialize
6
6
  # the Service with the given arguments and call the method "call" on the
7
7
  # instance.
8
+ # @example
9
+ # class ReverseService < Base
10
+ # def initialize(str)
11
+ # @str = str.to_s
12
+ # end
13
+ #
14
+ # def call
15
+ # @str.reverse
16
+ # end
17
+ # end
8
18
  class Base
19
+ # Creates a service object.
20
+ # Inherit from Base and implement this method.
21
+ # @example
22
+ # class IsFile < Base
23
+ # attr_reader :file
24
+ # def initialize(file)
25
+ # @file = file.to_s
26
+ # end
27
+ # def call
28
+ # File.file? file
29
+ # end
30
+ # end
31
+ #
32
+ # @param *args [Array<Object>] arguments
33
+ # @raise [NotImplementedError] if call is not implemented
34
+ def initialize(*args)
35
+ @args = args
36
+ end
37
+
9
38
  # A convenience class method to initialize Normalize with the given
10
39
  # arguments and call the method "call" on the instance.
40
+ # @param *args [Array] arguments to be passed to Base.new
11
41
  def self.call(*args)
12
42
  new(*args).call
13
43
  end
14
44
 
15
45
  # Inherit from Base and implement the call method
46
+ # @raise [NotImplementedError] if call is not implemented
16
47
  def call
17
48
  raise NotImplementedError
18
49
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'peach'
4
+ require 'pathname'
5
+
6
+ module YamlNormalizer
7
+ module Services
8
+ # Check is a service class that provides functionality to check if giving
9
+ # YAML files are already standardized (normalized).
10
+ # @exmaple
11
+ # check = YamlNormalizer::Services::Call.new('path/to/*.yml')
12
+ # result = check.call
13
+ class Check < Base
14
+ include Helpers::Normalize
15
+
16
+ # files is a sorted array of file path Strings
17
+ attr_reader :files
18
+
19
+ # Create a Check service object by calling .new and passing one or
20
+ # more Strings that are interpreted as file glob pattern.
21
+ # @param *args [Array<String>] a list of file glob patterns
22
+ def initialize(*args)
23
+ files = args.each_with_object([]) { |a, o| o << Dir[a.to_s] }
24
+ @files = files.flatten.sort.uniq
25
+ end
26
+
27
+ # Normalizes all YAML files defined on instantiation.
28
+ def call
29
+ files.peach do |file|
30
+ if IsYaml.call(file)
31
+ normalized?(file)
32
+ else
33
+ $stderr.puts "#{file} not a YAML file"
34
+ end
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def normalized?(file)
41
+ file = Pathname.new(file).relative_path_from(Pathname.new(Dir.pwd))
42
+ input = File.read(file)
43
+ norm = normalize_yaml(input)
44
+
45
+ if input.eql?(norm)
46
+ $stdout.puts "[PASSED] already normalized #{file}"
47
+ else
48
+ $stdout.puts "[FAILED] normalization suggested for #{file}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -4,17 +4,25 @@ require 'psych'
4
4
 
5
5
  module YamlNormalizer
6
6
  module Services
7
- # describe!
7
+ # IsYaml is a Service Class that provides functionality to check if a file
8
+ # is a parseable non-scalar YAML file.
9
+ # @exmaple
10
+ # is_yaml = YamlNormalizer::Services::IsYaml.new('path/to/file.yml')
11
+ # result = is_yaml.call
8
12
  class IsYaml < Base
13
+ # file is the file path String to be regarded
9
14
  attr_reader :file
10
15
 
16
+ # Create an IsYaml service object by calling .new and passing a file path
17
+ # String.
18
+ # @param file [String] file path to be regarded
11
19
  def initialize(file)
12
20
  @file = file.to_s
13
21
  end
14
22
 
15
23
  # Return true if given file is a valid YAML file
16
24
  def call
17
- file? && parsable? && !scalar?
25
+ file? && parseable? && !scalar?
18
26
  end
19
27
 
20
28
  private
@@ -25,7 +33,7 @@ module YamlNormalizer
25
33
 
26
34
  # The current implementation does not require parsable? to return a
27
35
  # boolean value
28
- def parsable?
36
+ def parseable?
29
37
  Psych.load_file(file)
30
38
  rescue Psych::SyntaxError
31
39
  false
@@ -4,13 +4,20 @@ require 'peach'
4
4
 
5
5
  module YamlNormalizer
6
6
  module Services
7
- # Normalize is a Service that provides functionality to
7
+ # Normalize is a service class that provides functionality to update giving
8
+ # YAML files to a standardized (normalized) format.
9
+ # @exmaple
10
+ # normalize = YamlNormalizer::Services::Normalize.new('path/to/*.yml')
11
+ # result = normalize.call
8
12
  class Normalize < Base
9
- attr_reader :files
13
+ include Helpers::Normalize
10
14
 
11
- using YamlNormalizer::Refinements::HashSortByKey
12
- using YamlNormalizer::Refinements::HashNamespaced
15
+ # files is a sorted array of file path Strings
16
+ attr_reader :files
13
17
 
18
+ # Create a Normalize service object by calling .new and passing one or
19
+ # more String that are interpreted as file glob pattern.
20
+ # @param *args [Array<String>] a list of file glob patterns
14
21
  def initialize(*args)
15
22
  files = args.each_with_object([]) { |a, o| o << Dir[a.to_s] }
16
23
  @files = files.flatten.sort.uniq
@@ -30,6 +37,7 @@ module YamlNormalizer
30
37
  private
31
38
 
32
39
  def normalize!(file)
40
+ file = Pathname.new(file).relative_path_from(Pathname.new(Dir.pwd))
33
41
  if stable?(input = File.read(file), norm = normalize_yaml(input))
34
42
  File.open(file, 'w') { |f| f.write(norm) }
35
43
  $stderr.puts "[NORMALIZED] #{file}"
@@ -38,11 +46,6 @@ module YamlNormalizer
38
46
  end
39
47
  end
40
48
 
41
- def normalize_yaml(yaml)
42
- hashes = Psych.parse_stream(yaml).transform
43
- hashes.map(&:sort_by_key).map(&:to_yaml).join
44
- end
45
-
46
49
  def stable?(yaml_a, yaml_b)
47
50
  parse(yaml_a).each_with_index.all? do |a, i|
48
51
  a.namespaced.eql?(parse(yaml_b).fetch(i).namespaced)
@@ -50,7 +53,9 @@ module YamlNormalizer
50
53
  end
51
54
 
52
55
  def parse(yaml)
53
- Psych.parse_stream(yaml).transform
56
+ ary = Psych.parse_stream(yaml).transform
57
+ ary.each { |hash| hash.extend(Ext::Namespaced) }
58
+ ary
54
59
  end
55
60
  end
56
61
  end
@@ -7,5 +7,6 @@ module YamlNormalizer
7
7
  end
8
8
 
9
9
  require 'yaml_normalizer/services/base'
10
+ require 'yaml_normalizer/services/check'
10
11
  require 'yaml_normalizer/services/is_yaml'
11
12
  require 'yaml_normalizer/services/normalize'
@@ -2,5 +2,5 @@
2
2
 
3
3
  module YamlNormalizer
4
4
  # The current Yaml Normalizer version
5
- VERSION = '0.1.0'
5
+ VERSION = '0.2.0'
6
6
  end
@@ -6,5 +6,6 @@ module YamlNormalizer
6
6
  end
7
7
 
8
8
  require 'yaml_normalizer/version'
9
- require 'yaml_normalizer/refinements'
9
+ require 'yaml_normalizer/ext'
10
+ require 'yaml_normalizer/helpers'
10
11
  require 'yaml_normalizer/services'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yaml_normalizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wolfgang Teuber
@@ -39,21 +39,21 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.5'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
47
+ version: '12.0'
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: '12.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake
56
+ name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -122,34 +122,6 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: cane
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: flay
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
125
  - !ruby/object:Gem::Dependency
154
126
  name: flog
155
127
  requirement: !ruby/object:Gem::Requirement
@@ -333,18 +305,21 @@ extra_rdoc_files: []
333
305
  files:
334
306
  - bin/yaml_normalizer
335
307
  - lib/yaml_normalizer.rb
308
+ - lib/yaml_normalizer/ext.rb
309
+ - lib/yaml_normalizer/ext/namespaced.rb
310
+ - lib/yaml_normalizer/ext/sort_by_key.rb
311
+ - lib/yaml_normalizer/helpers.rb
312
+ - lib/yaml_normalizer/helpers/normalize.rb
336
313
  - lib/yaml_normalizer/rake_task.rb
337
- - lib/yaml_normalizer/refinements.rb
338
- - lib/yaml_normalizer/refinements/hash_namespaced.rb
339
- - lib/yaml_normalizer/refinements/hash_sort_by_key.rb
340
314
  - lib/yaml_normalizer/services.rb
341
315
  - lib/yaml_normalizer/services/base.rb
316
+ - lib/yaml_normalizer/services/check.rb
342
317
  - lib/yaml_normalizer/services/is_yaml.rb
343
318
  - lib/yaml_normalizer/services/normalize.rb
344
319
  - lib/yaml_normalizer/version.rb
345
320
  homepage: https://github.com/Sage/yaml_normalizer
346
321
  licenses:
347
- - MIT
322
+ - Apache-2.0
348
323
  metadata: {}
349
324
  post_install_message:
350
325
  rdoc_options: []
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YamlNormalizer
4
- module Refinements
5
- # Refine Hash to add method sort_by_key
6
- module HashNamespaced
7
- refine Hash do
8
- # Transforms a tree-shaped hash into a plain key-value pair hash,
9
- # separating tree levels with a dot.
10
- # @examples
11
- # {a: {b: {c: 1}}, b:{x: 2, y: {ok: true}, z: 4}}.namespaced
12
- # => {"a.b.c"=>1, "b.x"=>2, "b.y.ok"=>true, "b.z"=>4}
13
- def namespaced(namespace = [], tree = {})
14
- each do |key, value|
15
- child_ns = namespace.dup << key
16
- if value.is_a?(Hash)
17
- value.namespaced child_ns, tree
18
- else
19
- tree[child_ns.join('.')] = value
20
- end
21
- end
22
- tree
23
- end
24
- end
25
- end
26
- end
27
- end
28
-
29
- # mutant doen't support Refinements use monky-patch for mutation testing
30
- # class Hash
31
- # # Transforms a tree-shaped hash into a plain key-value pair hash,
32
- # # separating tree levels with a dot.
33
- # # @examples
34
- # # {a: {b: {c: 1}}, b:{x: 2, y: {ok: true}, z: 4}}.namespaced
35
- # # => {"a.b.c"=>1, "b.x"=>2, "b.y.ok"=>true, "b.z"=>4}
36
- # def namespaced(namespace = [], tree = {})
37
- # each do |key, value|
38
- # child_ns = namespace.dup << key
39
- # if value.is_a?(Hash)
40
- # value.namespaced child_ns, tree
41
- # else
42
- # tree[child_ns.join('.')] = value
43
- # end
44
- # end
45
- # tree
46
- # end
47
- # end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YamlNormalizer
4
- module Refinements
5
- # Refine Hash to add method sort_by_key
6
- module HashSortByKey
7
- refine Hash do
8
- # Sorts entries alphabetically by key and returns a new Hash
9
- # sort_by_key does not modify the Hash it's called on.
10
- def sort_by_key(recursive = true, &block)
11
- keys.sort(&block).each_with_object({}) do |key, seed|
12
- seed[key] = self[key]
13
- if recursive && seed[key].is_a?(Hash)
14
- seed[key] = seed[key].sort_by_key(true, &block)
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
22
-
23
- # mutant doen't support Refinements use monky-patch for mutation testing
24
- # class Hash
25
- # # Sorts entries alphabetically by key and returns a new Hash
26
- # # sort_by_key does not modify the Hash it's called on.
27
- # def sort_by_key(recursive = true, &block)
28
- # keys.sort(&block).each_with_object({}) do |key, seed|
29
- # seed[key] = self[key]
30
- # if recursive && seed[key].is_a?(Hash)
31
- # seed[key] = seed[key].sort_by_key(true, &block)
32
- # end
33
- # end
34
- # end
35
- # end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YamlNormalizer
4
- # Refinements holds all refinements used for Yaml Normalizer
5
- module Refinements
6
- end
7
- end
8
-
9
- require 'yaml_normalizer/refinements/hash_sort_by_key'
10
- require 'yaml_normalizer/refinements/hash_namespaced'