opt_parse_validator 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +4 -0
  5. data/.simplecov +4 -0
  6. data/.travis.yml +15 -0
  7. data/Gemfile +6 -0
  8. data/README.md +40 -0
  9. data/Rakefile +9 -0
  10. data/lib/opt_parse_validator/hacks.rb +15 -0
  11. data/lib/opt_parse_validator/options_file.rb +62 -0
  12. data/lib/opt_parse_validator/opts/base.rb +74 -0
  13. data/lib/opt_parse_validator/opts/boolean.rb +20 -0
  14. data/lib/opt_parse_validator/opts/choice.rb +33 -0
  15. data/lib/opt_parse_validator/opts/credentials.rb +14 -0
  16. data/lib/opt_parse_validator/opts/directory_path.rb +10 -0
  17. data/lib/opt_parse_validator/opts/file_path.rb +24 -0
  18. data/lib/opt_parse_validator/opts/integer.rb +12 -0
  19. data/lib/opt_parse_validator/opts/path.rb +61 -0
  20. data/lib/opt_parse_validator/opts/positive_integer.rb +13 -0
  21. data/lib/opt_parse_validator/opts/proxy.rb +5 -0
  22. data/lib/opt_parse_validator/opts/string.rb +6 -0
  23. data/lib/opt_parse_validator/opts/uri.rb +24 -0
  24. data/lib/opt_parse_validator/opts/url.rb +9 -0
  25. data/lib/opt_parse_validator/opts.rb +3 -0
  26. data/lib/opt_parse_validator/version.rb +4 -0
  27. data/lib/opt_parse_validator.rb +77 -0
  28. data/opt_parse_validator.gemspec +32 -0
  29. data/spec/fixtures/options_file/default.json +4 -0
  30. data/spec/fixtures/options_file/malformed.json +4 -0
  31. data/spec/fixtures/options_file/override.yml +1 -0
  32. data/spec/fixtures/options_file/unsupported.ext +1 -0
  33. data/spec/fixtures/r.txt +1 -0
  34. data/spec/fixtures/rwx.txt +1 -0
  35. data/spec/lib/opt_parse_validator/options_file_spec.rb +50 -0
  36. data/spec/lib/opt_parse_validator/opts/base_spec.rb +169 -0
  37. data/spec/lib/opt_parse_validator/opts/boolean_spec.rb +36 -0
  38. data/spec/lib/opt_parse_validator/opts/choice_spec.rb +78 -0
  39. data/spec/lib/opt_parse_validator/opts/credentials_spec.rb +23 -0
  40. data/spec/lib/opt_parse_validator/opts/direcyory_path_spec.rb +25 -0
  41. data/spec/lib/opt_parse_validator/opts/file_path_spec.rb +93 -0
  42. data/spec/lib/opt_parse_validator/opts/integer_spec.rb +19 -0
  43. data/spec/lib/opt_parse_validator/opts/path_spec.rb +7 -0
  44. data/spec/lib/opt_parse_validator/opts/positive_integer_spec.rb +19 -0
  45. data/spec/lib/opt_parse_validator/opts/proxy_spec.rb +12 -0
  46. data/spec/lib/opt_parse_validator/opts/uri_spec.rb +58 -0
  47. data/spec/lib/opt_parse_validator/opts/url_spec.rb +28 -0
  48. data/spec/lib/opt_parse_validator/version_spec.rb +7 -0
  49. data/spec/lib/opt_parse_validator_spec.rb +152 -0
  50. data/spec/spec_helper.rb +25 -0
  51. metadata +213 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1b0a34c11c84d6fa32580ed925dac42346cee747
4
+ data.tar.gz: 7c50ea36943042d5cf7f8b77c15fd93b0969339c
5
+ SHA512:
6
+ metadata.gz: 051c726116d357bd876f87d9a113ba3c00f53a2b146e92e69d2447bef77de471fe2150f2c834356d52a1ec0b5b14f0b8e94e3177e3e6c84190ceac2068be1579
7
+ data.tar.gz: 910103742d3c7cfab15980043a02a169a9708f4ed3f11086ee280eec9d8cdd57621d82a8cf04f7739083f7384fd50c98e45ac2e5a129175c5a5461f52d2c8ff6
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ coverage
2
+ Gemfile.lock
3
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --fail-fast
data/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ LineLength:
2
+ Enabled: false
3
+ MethodLength:
4
+ Max: 20
data/.simplecov ADDED
@@ -0,0 +1,4 @@
1
+ SimpleCov.start do
2
+ add_filter '/spec/'
3
+ add_filter '_helper.rb'
4
+ end
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.0
5
+ - 2.1.1
6
+ - 2.1.2
7
+ - ruby-head
8
+ matrix:
9
+ allow_failures:
10
+ - rvm: ruby-head
11
+ before_script:
12
+ - chmod 0400 spec/fixtures/r.txt
13
+ script:
14
+ - bundle exec rspec
15
+ - bundle exec rubocop
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ group :test do
5
+ gem 'coveralls', require: false
6
+ end
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ OptParseValidator
2
+ =================
3
+
4
+ [![Build Status](https://img.shields.io/travis/wpscanteam/OptParseValidator.svg)](https://travis-ci.org/wpscanteam/OptParseValidator)
5
+ [![Coverage Status](https://img.shields.io/coveralls/wpscanteam/OptParseValidator.svg)](https://coveralls.io/r/wpscanteam/OptParseValidator?branch=master)
6
+ [![Code Climate](https://img.shields.io/codeclimate/github/wpscanteam/OptParseValidator.svg)](https://codeclimate.com/github/wpscanteam/OptParseValidator)
7
+ [![Dependency Status](https://img.shields.io/gemnasium/wpscanteam/OptParseValidator.svg)](https://gemnasium.com/wpscanteam/OptParseValidator)
8
+
9
+
10
+ ### Available Validators & associated attributes:
11
+ - Boolean
12
+ - Choice
13
+ - :choices (mandatory)
14
+ - :case_sensitive
15
+ - Credentials
16
+ - Directory Path
17
+ - :exists
18
+ - :executable
19
+ - :readable
20
+ - :writable
21
+ - File Path
22
+ - :exists
23
+ - :executable
24
+ - :readable
25
+ - :writable
26
+ - Integer
27
+ - Positive Integer
28
+ - Path
29
+ - :file
30
+ - :directory
31
+ - :exists
32
+ - :executable
33
+ - :readable
34
+ - :writable
35
+ - Proxy
36
+ - :protocols
37
+ - String
38
+ - URI
39
+ - :protocols
40
+ - URL
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RuboCop::RakeTask.new
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ # Run rubocop & rspec before the build
9
+ task build: [:rubocop, :spec]
@@ -0,0 +1,15 @@
1
+ class OptionParser
2
+ # Hack to suppress the completion (expect for the -h/--help) which was leading to
3
+ # unwanted behaviours
4
+ # See https://github.com/wpscanteam/CMSScanner/issues/2
5
+ module Completion
6
+ class << self
7
+ alias_method :original_candidate, :candidate
8
+
9
+ def candidate(key, icase = false, pat = nil, &block)
10
+ # Maybe also do this for -v/--version ?
11
+ key == 'h' ? original_candidate('help', icase, pat, &block) : []
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,62 @@
1
+ require 'json'
2
+ require 'yaml'
3
+
4
+ module OptParseValidator
5
+ # TODO
6
+ class OptParser < OptionParser
7
+ def options_files
8
+ @options_files ||= []
9
+ end
10
+
11
+ def load_options_files
12
+ files_data = {}
13
+
14
+ options_files.each do |file|
15
+ data = parse_file(file)
16
+ files_data.merge!(data) if data
17
+ end
18
+
19
+ @opts.each do |opt|
20
+ # Annoying thing: the hash returned from parse_file is a string-full {"key"=>"value"}
21
+ # and not a ruby hash {key: value} :/ As a result, symbol.to_s has to be used
22
+ next unless files_data.key?(opt.to_sym.to_s)
23
+
24
+ @results[opt.to_sym] = opt.normalize(opt.validate(files_data[opt.to_sym.to_s]))
25
+ end
26
+ end
27
+
28
+ protected
29
+
30
+ # @param [ String ] file_path
31
+ #
32
+ # @return [ Hash ]
33
+ def parse_file(file_path)
34
+ return unless File.exist?(file_path)
35
+
36
+ file_ext = File.extname(file_path).delete('.')
37
+ method_to_call = "parse_#{file_ext}"
38
+
39
+ fail "The format #{file_ext} is not supported" unless respond_to?(method_to_call, true) # The true allows to check protected & private methods
40
+
41
+ begin
42
+ method(method_to_call).call(file_path)
43
+ rescue
44
+ raise "Parse Error, #{file_path} seems to be malformed"
45
+ end
46
+ end
47
+
48
+ # @param [ String ] file_path
49
+ #
50
+ # @return [ Hash ]
51
+ def parse_json(file_path)
52
+ JSON.parse(File.read(file_path))
53
+ end
54
+
55
+ # @param [ String ] file_path
56
+ #
57
+ # @return [ Hash ]
58
+ def parse_yml(file_path)
59
+ YAML.load_file(file_path)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,74 @@
1
+ module OptParseValidator
2
+ # Base Option
3
+ # This Option should not be called, children should be used.
4
+ class OptBase
5
+ attr_writer :required
6
+ attr_reader :option, :attrs
7
+
8
+ # @param [ Array ] option See OptionParser#on
9
+ # @param [ Hash ] attrs
10
+ # @option attrs [ Boolean ] :required
11
+ # @option attrs [ Mixed ] :default The default value to use if the option is not supplied
12
+ # @option attrs [ Boolean ] :to_sym If true, returns the symbol of the validated value
13
+ # @option attrs [ Array<Symbol> ] :normalize See #normalize
14
+ #
15
+ # @note The :default and :normalize 'logics' are done in OptParseValidator::OptParser#add_option
16
+ def initialize(option, attrs = {})
17
+ @option = option
18
+ @attrs = attrs
19
+ end
20
+
21
+ # @return [ Boolean ]
22
+ def required?
23
+ @required || attrs[:required]
24
+ end
25
+
26
+ # @param [ String ] value
27
+ def validate(value)
28
+ fail 'Empty option value supplied' if value.nil? || value.to_s.empty?
29
+ value
30
+ end
31
+
32
+ # Apply each methods from attrs[:normalize] to the value if possible
33
+ # User input should not be used in this attrs[:normalize]
34
+ #
35
+ # e.g: normalize: :to_sym will return the symbol of the value
36
+ # normalize: [:to_sym, :upcase] Will return the upercased symbol
37
+ #
38
+ # @param [ Mixed ] value
39
+ #
40
+ # @return [ Mixed ]
41
+ def normalize(value)
42
+ [*attrs[:normalize]].each do |method|
43
+ next unless method.is_a?(Symbol)
44
+
45
+ value = value.send(method) if value.respond_to?(method)
46
+ end
47
+
48
+ value
49
+ end
50
+
51
+ # @return [ Symbol ]
52
+ def to_sym
53
+ unless @symbol
54
+ long_option = to_long
55
+
56
+ fail "Could not find option symbol for #{option}" unless long_option
57
+
58
+ @symbol = long_option.gsub(/^--/, '').gsub(/-/, '_').to_sym
59
+ end
60
+ @symbol
61
+ end
62
+
63
+ # @return [ String ] The raw long option (e.g: --proxy)
64
+ def to_long
65
+ option.each do |option_attr|
66
+ if option_attr =~ /^--/
67
+ return option_attr.gsub(/ .*$/, '')
68
+ .gsub(/\[[^\]]+\]/, '')
69
+ end
70
+ end
71
+ nil
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,20 @@
1
+ module OptParseValidator
2
+ # Implementation of the Boolean Option
3
+ class OptBoolean < OptBase
4
+ TRUE_PATTERN = /\A(true|t|yes|y|1)\z/i
5
+ FALSE_PATTERN = /\A(false|f|no|n|0)\z/i
6
+
7
+ # @return [ Boolean ]
8
+ def validate(value)
9
+ value = value.to_s
10
+
11
+ if value.match(TRUE_PATTERN)
12
+ return true
13
+ elsif value.match(FALSE_PATTERN)
14
+ return false
15
+ else
16
+ fail 'Invalid boolean value, expected true|t|yes|y|1|false|f|no|n|0'
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ module OptParseValidator
2
+ # Implementation of the Choice Option
3
+ class OptChoice < OptBase
4
+ # @param [ Array ] option See OptBase#new
5
+ # @param [ Hash ] attrs
6
+ # :choices [ Array ] The available choices (mandatory)
7
+ # :case_sensitive [ Boolean ] Default: false
8
+ def initialize(option, attrs = {})
9
+ fail 'The :choices attribute is mandatory' unless attrs.key?(:choices)
10
+ fail 'The :choices attribute must be an array' unless attrs[:choices].is_a?(Array)
11
+
12
+ super(option, attrs)
13
+ end
14
+
15
+ # @return [ String ]
16
+ # If :case_sensitive if false (or nil), the downcased value of the choice
17
+ # will be returned
18
+ def validate(value)
19
+ value = value.to_s
20
+ choices = attrs[:choices]
21
+
22
+ unless attrs[:case_sensitive]
23
+ value.downcase!
24
+ choices.map!(&:downcase)
25
+ end
26
+
27
+ fail "'#{value}' is not a valid choice, expected one " \
28
+ "of the followings: #{choices.join(',')}" unless choices.include?(value)
29
+
30
+ value
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,14 @@
1
+ module OptParseValidator
2
+ # Implementation of the Credentials Option
3
+ class OptCredentials < OptBase
4
+ # @return [ Hash ] A hash containing the :username and :password
5
+ def validate(value)
6
+ unless value.index(':')
7
+ fail 'Incorrect credentials format, username:password expected'
8
+ end
9
+ creds = value.split(':', 2)
10
+
11
+ { username: creds[0], password: creds[1] }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module OptParseValidator
2
+ # Implemetantion of the DirectoryPath Option
3
+ class OptDirectoryPath < OptPath
4
+ def initialize(option, attrs = {})
5
+ super(option, attrs)
6
+
7
+ @attrs.merge!(directory: true)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ module OptParseValidator
2
+ # Implementation of the FilePath Option
3
+ class OptFilePath < OptPath
4
+ # @param [ Array ] option See OptBase#new
5
+ # @param [ Hash ] attrs See OptPath#new
6
+ # :extensions [ Array | String ] The allowed extension(s)
7
+ def initialize(option, attrs = {})
8
+ super(option, attrs)
9
+
10
+ @attrs.merge!(file: true)
11
+ end
12
+
13
+ def allowed_attrs
14
+ # :extensions is put at the first place
15
+ [:extensions] + super
16
+ end
17
+
18
+ def check_extensions(path)
19
+ return if [*attrs[:extensions]].include?(path.extname.delete('.'))
20
+
21
+ fail "The extension of '#{path}' is not allowed"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ module OptParseValidator
2
+ # Implementation of the Integer Option
3
+ class OptInteger < OptBase
4
+ # @param [ String ] value
5
+ #
6
+ # @return [ Integer ]
7
+ def validate(value)
8
+ fail "#{value} is not an integer" if value.to_i.to_s != value
9
+ value.to_i
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,61 @@
1
+ module OptParseValidator
2
+ # Implementation of the Path Option
3
+ class OptPath < OptBase
4
+ # Initialize attrs:
5
+ #
6
+ # :exists if set to false, will ignore the file? and directory? checks
7
+ #
8
+ # :file Check if the path is a file
9
+ # :directory Check if the path is a directory
10
+ #
11
+ # :executable
12
+ # :readable
13
+ # :writable
14
+ #
15
+
16
+ # @param [ String ] value
17
+ #
18
+ # @return [ String ]
19
+ def validate(value)
20
+ path = Pathname.new(value)
21
+ allowed_attrs.each do |key|
22
+ method = "check_#{key}"
23
+ send(method, path) if self.respond_to?(method) && attrs[key]
24
+ end
25
+
26
+ path.to_s
27
+ end
28
+
29
+ def allowed_attrs
30
+ [:file, :directory, :executable, :readable, :writable]
31
+ end
32
+
33
+ # @param [ Pathname ] path
34
+ def check_file(path)
35
+ fail "'#{path}' is not a file" unless path.file? || attrs[:exists] == false
36
+ end
37
+
38
+ # @param [ Pathname ] path
39
+ def check_directory(path)
40
+ fail "'#{path}' is not a directory" unless path.directory? || attrs[:exists] == false
41
+ end
42
+
43
+ # @param [ Pathname ] path
44
+ def check_executable(path)
45
+ fail "'#{path}' is not executable" unless path.executable?
46
+ end
47
+
48
+ # @param [ Pathname ] path
49
+ def check_readable(path)
50
+ fail "'#{path}' is not readable" unless path.readable?
51
+ end
52
+
53
+ # If the path does not exist, it will check for the parent
54
+ # directory write permission
55
+ #
56
+ # @param [ Pathname ] path
57
+ def check_writable(path)
58
+ fail "'#{path}' is not writable" if path.exist? && !path.writable? || !path.parent.writable?
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,13 @@
1
+ module OptParseValidator
2
+ # Implementation of the Positive Integer Option
3
+ class OptPositiveInteger < OptInteger
4
+ # @param [ String ] value
5
+ #
6
+ # @return [ Integer ]
7
+ def validate(value)
8
+ i = super(value)
9
+ fail "#{i} is not > 0" unless i > 0
10
+ i
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module OptParseValidator
2
+ # Implementation of the Proxy Option
3
+ class OptProxy < OptURI
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ module OptParseValidator
2
+ # Alias of OptBase
3
+ # Used for convenience
4
+ class OptString < OptBase
5
+ end
6
+ end
@@ -0,0 +1,24 @@
1
+ module OptParseValidator
2
+ # Implementation of the URI Option
3
+ class OptURI < OptBase
4
+ def allowed_protocols
5
+ @allowed_protocols ||= [*attrs[:protocols]]
6
+ end
7
+
8
+ # @param [ String ] value
9
+ #
10
+ # @return [ String ]
11
+ def validate(value)
12
+ uri = Addressable::URI.parse(value)
13
+ protocols = allowed_protocols
14
+
15
+ unless protocols.empty? || protocols.include?(uri.scheme)
16
+ # For future refs: will have to check if the uri.scheme exists,
17
+ # otherwise it means that the value was empty
18
+ fail Addressable::URI::InvalidURIError
19
+ end
20
+
21
+ uri.to_s
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ module OptParseValidator
2
+ # Implementation of the URL Option
3
+ class OptURL < OptURI
4
+ # @return [ Array ] The allowed protocols
5
+ def allowed_protocols
6
+ %w(http https)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ %w(base string integer positive_integer choice boolean uri url proxy credentials path file_path directory_path).each do |opt|
2
+ require 'opt_parse_validator/opts/' + opt
3
+ end
@@ -0,0 +1,4 @@
1
+ # Gem Version
2
+ module OptParseValidator
3
+ VERSION = '0.0.2'
4
+ end
@@ -0,0 +1,77 @@
1
+ # Gems
2
+ require 'addressable/uri'
3
+ # Standard Libs
4
+ require 'optparse'
5
+ require 'pathname'
6
+ # Custom Libs
7
+ require 'opt_parse_validator/hacks'
8
+ require 'opt_parse_validator/opts'
9
+ require 'opt_parse_validator/version'
10
+ require 'opt_parse_validator/options_file'
11
+
12
+ # Gem namespace
13
+ module OptParseValidator
14
+ # Validator
15
+ class OptParser < OptionParser
16
+ attr_reader :symbols_used, :opts
17
+
18
+ def initialize(banner = nil, width = 32, indent = ' ' * 4)
19
+ @results = {}
20
+ @symbols_used = []
21
+ @opts = []
22
+
23
+ super(banner, width, indent)
24
+ end
25
+
26
+ # @param [ OptBase ] options
27
+ #
28
+ # @return [ void ]
29
+ def add(*options)
30
+ options.each { |option| add_option(option) }
31
+ end
32
+
33
+ # @param [ OptBase ] opt
34
+ #
35
+ # @return [ void ]
36
+ def add_option(opt)
37
+ fail "The option is not an OptBase, #{opt.class} supplied" unless opt.is_a?(OptBase)
38
+ fail "The option #{opt.to_sym} is already used !" if @symbols_used.include?(opt.to_sym)
39
+
40
+ @opts << opt
41
+ @symbols_used << opt.to_sym
42
+ # Set the default option value if it exists
43
+ @results[opt.to_sym] = opt.attrs[:default] if opt.attrs.key?(:default)
44
+
45
+ on(*opt.option) do |arg|
46
+ begin
47
+ @results[opt.to_sym] = opt.normalize(opt.validate(arg))
48
+ rescue => e
49
+ # Adds the long option name to the message
50
+ # e.g --proxy Invalid Scheme format.
51
+ raise e.class, "#{opt.to_long} #{e}"
52
+ end
53
+ end
54
+ end
55
+
56
+ # @return [ Hash ]
57
+ def results(argv = default_argv)
58
+ load_options_files
59
+ self.parse!(argv)
60
+ post_processing
61
+
62
+ @results
63
+ end
64
+
65
+ # Ensure that all required options are supplied
66
+ # Should be overriden to modify the behavior
67
+ #
68
+ # @return [ Void ]
69
+ def post_processing
70
+ @opts.each do |opt|
71
+ next unless opt.required? && !@results.key?(opt.to_sym)
72
+
73
+ fail "The option #{opt.to_sym} is required"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require 'opt_parse_validator/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'opt_parse_validator'
9
+ s.version = OptParseValidator::VERSION
10
+ s.platform = Gem::Platform::RUBY
11
+ s.required_ruby_version = '>= 2.0.0'
12
+ s.authors = ['WPScanTeam - Erwan le Rousseau']
13
+ s.email = ['erwan.lr@gmail.com']
14
+ s.summary = 'Testing Gem'
15
+ s.description = 'Testing Gem ...'
16
+ s.homepage = 'https://github.com/wpscanteam/OptParseValidator'
17
+ s.license = 'MIT'
18
+
19
+ s.files = `git ls-files -z`.split("\x0")
20
+ s.executables = s.files.grep(/^bin\//) { |f| File.basename(f) }
21
+ s.test_files = s.files.grep(/^(test|spec|features)\//)
22
+ s.require_paths = ['lib']
23
+
24
+ s.add_dependency 'addressable', '~> 2.3'
25
+
26
+ s.add_development_dependency 'rake'
27
+ s.add_development_dependency 'rspec', '~> 3.1'
28
+ s.add_development_dependency 'rspec-its'
29
+ s.add_development_dependency 'bundler', '~> 1.6'
30
+ s.add_development_dependency 'rubocop', '~> 0.26'
31
+ s.add_development_dependency 'simplecov', '~> 0.9'
32
+ end
@@ -0,0 +1,4 @@
1
+ {
2
+ "verbose": true,
3
+ "override_me": "I should be overriden"
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "verbose": true,
3
+ "":,
4
+ }
@@ -0,0 +1 @@
1
+ override_me: "Yeaa"
@@ -0,0 +1 @@
1
+ Unsupported file format
@@ -0,0 +1 @@
1
+ This file is a chmod 400
@@ -0,0 +1 @@
1
+ This file is a chmod 777