frise 0.2.0 → 0.3.0.pre

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
- SHA1:
3
- metadata.gz: 658ef151a4948ba72f32f7dc5b51f5ddb3e6fb69
4
- data.tar.gz: 8b7498f11685e3c5d1a4bbce70c732d8a62e8eb6
2
+ SHA256:
3
+ metadata.gz: 72db98e097cb7abccf1a1208a53efa9a2486d49d3f58422a70e6f32ac7cbb2a8
4
+ data.tar.gz: 52f15d4c10262d54dc7534fa35c16abb66ad33d0498ceff612cc78124154fcf4
5
5
  SHA512:
6
- metadata.gz: 998d82e9c1a58efb14b5edd44deb4c85c62ced21cec664f29cffa3753f3742fc9e876fad96c9c3902fa2fc6a55d57622695bfe579acb6abb246695f8f7fe8b91
7
- data.tar.gz: f1a5e4ee436e6081a93fd204cfd7ee434aeb3d6ada5e90853f42467cf6339ca8a6c4dbc0b8d4b335d4e1d75e211e965736f84010cc3ffb31e6c37b668fafce9c
6
+ metadata.gz: 75b318b997eb2ab66dada979b270e468430ca372982d035bba4de12a68a0622f6897d928e173b67d7e046be2ecdee0d7b1374e0a0d50da55e80354d60285eb9f
7
+ data.tar.gz: b25a7625181eaf4d90f202ca0aa9dc9095ada98318272c2d5c999beb8ea28e0e7af397b1612692bd18709a59dca4cab758d30ee515563806d6def511500243e7
@@ -1,2 +1,8 @@
1
+ AllCops:
2
+ TargetRubyVersion: '2.3'
1
3
  Metrics:
2
4
  Enabled: false
5
+ Naming/UncommunicativeBlockParamName:
6
+ Enabled: false
7
+ Naming/UncommunicativeMethodParamName:
8
+ Enabled: false
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.1
4
- - 2.2
5
3
  - 2.3
6
4
  - 2.4
5
+ - 2.5
@@ -1,4 +1,4 @@
1
- ### 0.2.0 (unreleased)
1
+ ### 0.2.0 (August 17, 2017)
2
2
 
3
3
  - New features
4
4
  - New schema types `$enum` and `$one_of` for specifying enumerations and values with multiple
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in frise.gemspec
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
 
3
5
  def load_if_available(req_path)
@@ -1,6 +1,6 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'frise/version'
6
6
 
@@ -18,14 +18,14 @@ Gem::Specification.new do |spec|
18
18
  f.match(%r{^(test|spec|features|example)/})
19
19
  end
20
20
  spec.require_paths = ['lib']
21
- spec.required_ruby_version = '>= 2.1.0'
21
+ spec.required_ruby_version = '>= 2.3.0'
22
22
 
23
23
  spec.add_dependency 'liquid', '~> 3.0'
24
24
 
25
25
  spec.add_development_dependency 'bundler', '~> 1.14'
26
26
  spec.add_development_dependency 'coveralls', '~> 0.8.21'
27
- spec.add_development_dependency 'simplecov', '~> 0.14.1'
28
- spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'rake', '~> 12.3'
29
28
  spec.add_development_dependency 'rspec', '~> 3.4'
30
- spec.add_development_dependency 'rubocop', '~> 0.49.1'
29
+ spec.add_development_dependency 'rubocop', '~> 0.53.0'
30
+ spec.add_development_dependency 'simplecov', '~> 0.14.1'
31
31
  end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'frise/defaults_loader'
4
+ require 'frise/loader/lazy'
2
5
  require 'frise/loader'
3
6
  require 'frise/parser'
4
7
  require 'frise/validator'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'frise/parser'
2
4
 
3
5
  module Frise
@@ -7,6 +9,8 @@ module Frise
7
9
  # defaults and apply them to configuration objects.
8
10
  module DefaultsLoader
9
11
  class << self
12
+ SYMBOLS = %w[$all $optional].freeze
13
+
10
14
  def widened_class(obj)
11
15
  class_name = obj.class.to_s
12
16
  return 'Boolean' if %w[TrueClass FalseClass].include? class_name
@@ -33,7 +37,7 @@ module Frise
33
37
  elsif defaults.class == Hash && config.class == Hash
34
38
  new_config = {}
35
39
  (config.keys + defaults.keys).uniq.each do |key|
36
- next if key.start_with?('$')
40
+ next if SYMBOLS.include?(key)
37
41
  new_config[key] = config[key]
38
42
  new_config[key] = merge_defaults_obj(new_config[key], defaults[key]) if defaults.key?(key)
39
43
  new_config[key] = merge_defaults_obj(new_config[key], defaults['$all']) unless new_config[key].nil?
@@ -1,60 +1,129 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'frise/defaults_loader'
4
+ require 'frise/loader/lazy'
2
5
  require 'frise/parser'
3
6
  require 'frise/validator'
4
7
 
5
8
  module Frise
6
9
  # The entrypoint for loading configs from files according to the conventions defined for Frise.
7
10
  #
8
- # The load method loads a configuration file, merges it with the applicable defaults and validates
9
- # its schema. Other methods in Loader perform only parts of the process.
11
+ # The load method loads a configuration file, merges the applicable includes and validates its schema.
10
12
  class Loader
11
- def initialize(schema_load_paths: [], defaults_load_paths: [], pre_loaders: [], validators: nil)
12
- @schema_load_paths = schema_load_paths
13
- @defaults_load_paths = defaults_load_paths
13
+ def initialize(include_sym: '$include', schema_sym: '$schema', pre_loaders: [], validators: nil, exit_on_fail: true)
14
+ @include_sym = include_sym
15
+ @schema_sym = schema_sym
14
16
  @pre_loaders = pre_loaders
15
17
  @validators = validators
18
+ @exit_on_fail = exit_on_fail
16
19
  end
17
20
 
18
- def load(config_file, exit_on_fail = true, symbol_table = {})
19
- config = Parser.parse(config_file, symbol_table) || {}
20
- config_name = File.basename(config_file)
21
+ def load(config_file, global_vars = {})
22
+ config = Parser.parse(config_file, global_vars)
23
+ return nil unless config
21
24
 
22
25
  @pre_loaders.each do |pre_loader|
23
26
  config = pre_loader.call(config)
24
27
  end
25
28
 
26
- config = merge_defaults(config, config_name, symbol_table)
27
- validate(config, config_name, exit_on_fail)
29
+ config = process_includes(config, [], config, global_vars) if @include_sym
30
+ config = process_schemas(config, [], global_vars) if @schema_sym
31
+ config
28
32
  end
29
33
 
30
- def merge_defaults(config, defaults_name, symbol_table = {})
31
- merge_defaults_at(config, [], defaults_name, symbol_table)
32
- end
34
+ private
33
35
 
34
- def merge_defaults_at(config, at_path, defaults_name, symbol_table = {})
35
- @defaults_load_paths.map do |defaults_dir|
36
- defaults_file = File.join(defaults_dir, defaults_name)
37
- config = DefaultsLoader.merge_defaults_at(
38
- config, at_path, defaults_file, symbol_table.merge(config)
39
- )
36
+ def process_includes(config, at_path, root_config, global_vars)
37
+ return config unless config.class == Hash
38
+
39
+ config, defaults_confs = extract_include(config)
40
+ if defaults_confs.empty?
41
+ config.map { |k, v| [k, process_includes(v, at_path + [k], root_config, global_vars)] }.to_h
42
+ else
43
+ Lazy.new do
44
+ defaults_confs.each do |defaults_conf|
45
+ extra_vars = (defaults_conf['vars'] || {}).map { |k, v| [k, root_config.dig(*v.split('.'))] }.to_h
46
+ extra_consts = defaults_conf['constants'] || {}
47
+ symbol_table = merge_at(root_config, at_path, config)
48
+ .merge(global_vars).merge(extra_vars).merge(extra_consts).merge('_this' => config)
49
+
50
+ config = DefaultsLoader.merge_defaults_obj(config, Parser.parse(defaults_conf['file'], symbol_table))
51
+ end
52
+ process_includes(config, at_path, merge_at(root_config, at_path, config), global_vars)
53
+ end
40
54
  end
41
- config
42
55
  end
43
56
 
44
- def validate(config, schema_name, exit_on_fail = true)
45
- validate_at(config, [], schema_name, exit_on_fail)
57
+ def process_schema_includes(schema, global_vars)
58
+ return schema unless schema.class == Hash
59
+
60
+ schema, included_schemas = extract_include(schema)
61
+ if included_schemas.empty?
62
+ schema.map { |k, v| [k, process_schema_includes(v, global_vars)] }.to_h
63
+ else
64
+ included_schemas.each do |defaults_conf|
65
+ schema = Parser.parse(defaults_conf['file'], global_vars).merge(schema)
66
+ end
67
+ process_schema_includes(schema, global_vars)
68
+ end
46
69
  end
47
70
 
48
- def validate_at(config, at_path, schema_name, exit_on_fail = true)
49
- @schema_load_paths.map do |schema_dir|
50
- schema_file = File.join(schema_dir, schema_name)
51
- errors = Validator.validate_at(config, at_path, schema_file,
52
- validators: @validators,
53
- print: exit_on_fail,
54
- fatal: exit_on_fail)
71
+ def process_schemas(config, at_path, global_vars)
72
+ return config unless config.class == Hash
73
+
74
+ config = config.map do |k, v|
75
+ new_v = process_schemas(v, at_path + [k], global_vars)
76
+ return nil if !v.nil? && new_v.nil?
77
+ [k, new_v]
78
+ end.to_h
79
+
80
+ config, schema_files = extract_schema(config)
81
+ schema_files.each do |schema_file|
82
+ schema = Parser.parse(schema_file, global_vars)
83
+ schema = process_schema_includes(schema, global_vars)
84
+
85
+ errors = Validator.validate_obj(config,
86
+ schema,
87
+ path_prefix: at_path,
88
+ validators: @validators,
89
+ print: @exit_on_fail,
90
+ fatal: @exit_on_fail)
55
91
  return nil if errors.any?
56
92
  end
57
93
  config
58
94
  end
95
+
96
+ def extract_schema(config)
97
+ extract_special(config, @schema_sym) do |value|
98
+ case value
99
+ when String then value
100
+ else raise "Illegal value for a #{@schema_sym} element: #{value.inspect}"
101
+ end
102
+ end
103
+ end
104
+
105
+ def extract_include(config)
106
+ extract_special(config, @include_sym) do |value|
107
+ case value
108
+ when Hash then value
109
+ when String then { 'file' => value }
110
+ else raise "Illegal value for a #{@include_sym} element: #{value.inspect}"
111
+ end
112
+ end
113
+ end
114
+
115
+ def extract_special(config, key)
116
+ case config[key]
117
+ when nil then [config, []]
118
+ when Array then [config.reject { |k| k == key }, config[key].map { |e| yield e }]
119
+ else raise "Illegal value for #{key}: #{config[key].inspect}"
120
+ end
121
+ end
122
+
123
+ def merge_at(config, at_path, to_merge)
124
+ return config.merge(to_merge) if at_path.empty?
125
+ head, *tail = at_path
126
+ config.merge(head => merge_at(config[head], tail, to_merge))
127
+ end
59
128
  end
60
129
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Frise
4
+ class Loader
5
+ # A basic proxy object.
6
+ class Lazy < BasicObject
7
+ def initialize(&callable)
8
+ @callable = callable
9
+ end
10
+
11
+ def __target_object__
12
+ @__target_object__ ||= @callable.call
13
+ end
14
+
15
+ # rubocop:disable Style/MethodMissing
16
+ def method_missing(method_name, *args, &block)
17
+ __target_object__.send(method_name, *args, &block)
18
+ end
19
+ # rubocop:enable Style/MethodMissing
20
+ end
21
+ end
22
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'liquid'
2
4
  require 'yaml'
3
5
 
@@ -9,9 +11,15 @@ module Frise
9
11
  def parse(file, symbol_table = nil)
10
12
  return nil unless File.file? file
11
13
  content = File.open(file).read
12
- content = Liquid::Template.parse(content).render symbol_table if symbol_table
14
+ content = Liquid::Template.parse(content).render with_internal_vars(file, symbol_table) if symbol_table
13
15
  YAML.safe_load(content, [], [], true) || {}
14
16
  end
17
+
18
+ private
19
+
20
+ def with_internal_vars(file, symbol_table)
21
+ symbol_table.merge('_file_dir' => File.dirname(file))
22
+ end
15
23
  end
16
24
  end
17
25
  end
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'frise/parser'
4
5
  require 'set'
@@ -164,32 +165,36 @@ module Frise
164
165
  end
165
166
 
166
167
  def self.validate_obj(config, schema, options = {})
167
- validator = Validator.new(config, options[:validators])
168
- validator.validate_object('', config, schema)
168
+ validate_obj_at(config, [], schema, options)
169
+ end
170
+
171
+ def self.validate_obj_at(config, at_path, schema, path_prefix: nil, validators: nil, print: nil, fatal: nil, raise_error: nil)
172
+ schema = parse_symbols(schema)
173
+ at_path.reverse.each { |key| schema = { key => schema, :allow_unknown_keys => true } }
174
+
175
+ validator = Validator.new(config, validators)
176
+ validator.validate_object((path_prefix || []).join('.'), config, schema)
169
177
 
170
178
  if validator.errors.any?
171
- if options[:print]
179
+ if print
172
180
  puts "#{validator.errors.length} config error(s) found:"
173
181
  validator.errors.each do |error|
174
182
  puts " - #{error}"
175
183
  end
176
184
  end
177
185
 
178
- exit 1 if options[:fatal]
179
- raise ValidationError.new(validator.errors), 'Invalid configuration' if options[:raise_error]
186
+ exit 1 if fatal
187
+ raise ValidationError.new(validator.errors), 'Invalid configuration' if raise_error
180
188
  end
181
189
  validator.errors
182
190
  end
183
191
 
184
192
  def self.validate(config, schema_file, options = {})
185
- schema = parse_symbols(Parser.parse(schema_file) || { allow_unknown_keys: true })
186
- validate_obj(config, schema, options)
193
+ validate_obj_at(config, [], Parser.parse(schema_file) || { allow_unknown_keys: true }, options)
187
194
  end
188
195
 
189
196
  def self.validate_at(config, at_path, schema_file, options = {})
190
- schema = parse_symbols(Parser.parse(schema_file) || { allow_unknown_keys: true })
191
- at_path.reverse.each { |key| schema = { key => schema, :allow_unknown_keys => true } }
192
- validate_obj(config, schema, options)
197
+ validate_obj_at(config, at_path, Parser.parse(schema_file) || { allow_unknown_keys: true }, options)
193
198
  end
194
199
  end
195
200
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Frise
2
- VERSION = '0.2.0'.freeze
4
+ VERSION = '0.3.0.pre'
3
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frise
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - ShiftForward
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-17 00:00:00.000000000 Z
11
+ date: 2018-04-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -53,61 +53,61 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.8.21
55
55
  - !ruby/object:Gem::Dependency
56
- name: simplecov
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.14.1
61
+ version: '12.3'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.14.1
68
+ version: '12.3'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rake
70
+ name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '10.0'
75
+ version: '3.4'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '10.0'
82
+ version: '3.4'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rspec
84
+ name: rubocop
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.4'
89
+ version: 0.53.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.4'
96
+ version: 0.53.0
97
97
  - !ruby/object:Gem::Dependency
98
- name: rubocop
98
+ name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 0.49.1
103
+ version: 0.14.1
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 0.49.1
110
+ version: 0.14.1
111
111
  description:
112
112
  email:
113
113
  - info@shiftforward.eu
@@ -128,6 +128,7 @@ files:
128
128
  - lib/frise.rb
129
129
  - lib/frise/defaults_loader.rb
130
130
  - lib/frise/loader.rb
131
+ - lib/frise/loader/lazy.rb
131
132
  - lib/frise/parser.rb
132
133
  - lib/frise/validator.rb
133
134
  - lib/frise/version.rb
@@ -143,15 +144,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
143
144
  requirements:
144
145
  - - ">="
145
146
  - !ruby/object:Gem::Version
146
- version: 2.1.0
147
+ version: 2.3.0
147
148
  required_rubygems_version: !ruby/object:Gem::Requirement
148
149
  requirements:
149
- - - ">="
150
+ - - ">"
150
151
  - !ruby/object:Gem::Version
151
- version: '0'
152
+ version: 1.3.1
152
153
  requirements: []
153
154
  rubyforge_project:
154
- rubygems_version: 2.6.11
155
+ rubygems_version: 2.7.6
155
156
  signing_key:
156
157
  specification_version: 4
157
158
  summary: Ruby config library with schema validation, default values and templating