yaml_normalizer 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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'