nugrant 2.0.0.pre1 → 2.0.0.pre2

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: 9f14bf2a70810293d967c9e9d24b60408880e5b0
4
- data.tar.gz: 1d24d5cfa15fde530b4daab7743adb9b29bf74a4
3
+ metadata.gz: 969a898ed0ac4d45b6adc22f43304d80a61d3eda
4
+ data.tar.gz: a2f9140bab38bd74f9297cda110572d49c0f8425
5
5
  SHA512:
6
- metadata.gz: 4ade947b4d55e761d3ec22065b34b680cac998f9544fa98e30a309ce9c65d4f2a76bde76233633e9eb630725c0fc622ea6c8b163332af8401347af8d0dd409d9
7
- data.tar.gz: 20d4f38d519f1e15f487d0bdecd6d74246a8b748d4933f98285504587360c24cd5936c111fb85dfb578079abb9a28a47e7f8dccf7b22655510aa77a87a91725b
6
+ metadata.gz: ba35c594059cb9c04fef4495e55ca55fddbdafe95041335cd6ddec5e4234d6c65150f6418d407fc3d9dad28cff383a7402c369d0c429f3541eed7c00c7ed7dfe
7
+ data.tar.gz: b5684cd172236eb57add8c9492fc8818b23707f813adbc2c9dc21ce951f5b8c4f949646e208a2acdb510f1ef53ea68ddb4491872f4af96fd530cacf2c38b03e1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # 2.0.0 (In progress)
2
2
 
3
+ * Added possibility to change array merge strategy. This can
4
+ be used in Vagrant by doing `config.user.array_merge_strategy = <strategy>`
5
+ where valid strategies are:
6
+
7
+ * :replace => Replace current values by new ones
8
+ * :extend => Merge current values with new ones
9
+ * :concat => Append new values to current ones
10
+
11
+ * Better handling in Vagrant of cases where the vagrant user
12
+ file cannot be parsed correctly. This is now reported
13
+ as an error in Vagrant an nicely displayed with the path
14
+ of the offending file and the parser error message.
15
+
16
+ * Better handling of how global Nugrant options are passed and
17
+ handled. Everything is now located in the `Nugrant::Config`
18
+ object and used by everything that need some configuration
19
+ parameters.
20
+
3
21
  * It is now possible to customize key error handling by passing
4
22
  an options hash with key `:key_error` and a `Proc` value.
5
23
 
data/README.md CHANGED
@@ -126,6 +126,10 @@ In text, this means that current parameters overrides user
126
126
  parameters, user parameters overrides system parameters and
127
127
  finally system parameters overrides defaults parameters.
128
128
 
129
+ When two keys that are merged together points to Array values,
130
+ the default operation is to replace current Array by
131
+ overriding one. The default merge strategy can be customized.
132
+
129
133
  ### Vagrant
130
134
 
131
135
  All examples shown here are for Vagrant 1.1+. They have
@@ -323,6 +327,36 @@ If the user decides to change it, he just has to set it in his
323
327
  own `.vagrantuser` and it will override the default value defined
324
328
  in the Vagrantfile.
325
329
 
330
+ #### Array merge strategies
331
+
332
+ As stated previously, when two arrays are merged together,
333
+ the default strategy is to replace current array with new one.
334
+
335
+ However, in some certain circumstances, you may need another
336
+ behavior. That is why we also provide two other strategies
337
+ that can be used.
338
+
339
+ * `:concat`
340
+ With this strategy, new array is appended to the end
341
+ of current array when merged. The `Array` `+` operator
342
+ is used to concatenante the two arrays.
343
+
344
+ * `:extend`
345
+ With this strategy, current array is extended with values
346
+ from new one. The `Array` `|` (union) operator
347
+ is used to extend the array.
348
+
349
+ You can use the following snippet directly within your Vagrantfile
350
+ to change the array merge strategy:
351
+
352
+ Vagrant.configure("2") do |config|
353
+ config.user.array_merge_strategy = :extend
354
+
355
+ config.ssh.port config.user.vm.ssh_port
356
+ end
357
+
358
+ If you specify an unsupported strategy, nothing will happen.
359
+
326
360
  #### Commands
327
361
 
328
362
  In this section, we describe the various vagrant commands defined
data/lib/nugrant/bag.rb CHANGED
@@ -7,49 +7,41 @@ module Nugrant
7
7
  # differences with a normal Hash are indifferent access
8
8
  # (symbol or string) and method access (via method call).
9
9
  #
10
+ # Hash objects in the map are converted to Bag. This ensure
11
+ # proper nesting of functionality.
12
+ #
10
13
  # =| Arguments
11
14
  # * `elements`
12
15
  # The initial elements the bag should be built with it.'
13
16
  # Must be an object responding to `each` and accepting
14
- # a block with two arguments: `key, value`.]. Defaults to
17
+ # a block with two arguments: `key, value`. Defaults to
15
18
  # the empty hash.
16
19
  #
17
- # * `options`
18
- # An options hash where some customization option can be passed.
19
- # Defaults to an empty hash, see options for specific option default
20
- # values.
21
- #
22
- # =| Options
23
- # * `:key_error`
24
- # A callable object receiving a single parameter `key` that is
25
- # called when a key cannot be found in the Bag. The received key
26
- # is already converted to a symbol. If the callable does not
27
- # raise an exception, the result of it's execution is returned.
28
- # The default value is a callable that throws a KeyError exception.
20
+ # * `config`
21
+ # A Nugrant::Config object or hash passed to Nugrant::Config
22
+ # constructor. Used for `key_error` handler.
29
23
  #
30
- def initialize(elements = {}, options = {})
24
+ def initialize(elements = {}, config = {})
31
25
  super()
32
26
 
33
- @__key_error = options[:key_error] || Proc.new do |key|
34
- raise KeyError, "Undefined parameter '#{key}'" if not key?(key)
35
- end
27
+ @__config = Config::convert(config)
36
28
 
37
29
  (elements || {}).each do |key, value|
38
- self[key] = value.kind_of?(Hash) ? Bag.new(value, options) : value
30
+ self[key] = value.kind_of?(Hash) ? Bag.new(value, config) : value
39
31
  end
40
32
  end
41
33
 
42
34
  def method_missing(method, *args, &block)
43
- return self[method]
35
+ self[method]
44
36
  end
45
37
 
46
38
  ##
47
- ### Hash Overriden Methods (for string & symbol indifferent access)
39
+ ### Hash Overridden Methods (for string & symbol indifferent access)
48
40
  ##
49
41
 
50
42
  def [](input)
51
43
  key = __convert_key(input)
52
- return @__key_error.call(key) if not key?(key)
44
+ return @__config.key_error.call(key) if not key?(key)
53
45
 
54
46
  super(key)
55
47
  end
@@ -63,24 +55,10 @@ module Nugrant
63
55
  end
64
56
 
65
57
  ##
66
- # This method first start by converting the `input` parameter
67
- # into a bag. It will then *deep* merge current values with
68
- # the new ones coming from the `input`.
58
+ # This method deeply merge two instance together
69
59
  #
70
- # The array merge strategy is by default to replace current
71
- # values with new ones. You can use option `:array_strategy`
72
- # to change this default behavior.
73
60
  #
74
- # +Options+
75
- # * :array_strategy
76
- # * :replace (Default) => Replace current values by new ones
77
- # * :extend => Merge current values with new ones
78
- # * :concat => Append new values to current ones
79
- #
80
- def merge!(input, options = {})
81
- options = {:array_strategy => :replace}.merge(options)
82
-
83
- array_strategy = options[:array_strategy]
61
+ def merge!(input)
84
62
  input.each do |key, value|
85
63
  current = __get(key)
86
64
  case
@@ -88,10 +66,10 @@ module Nugrant
88
66
  self[key] = value
89
67
 
90
68
  when current.kind_of?(Hash) && value.kind_of?(Hash)
91
- current.merge!(value, options)
69
+ current.merge!(value)
92
70
 
93
71
  when current.kind_of?(Array) && value.kind_of?(Array)
94
- self[key] = send("__#{array_strategy}_array_merge", current, value)
72
+ self[key] = send("__#{@__config.array_merge_strategy}_array_merge", current, value)
95
73
 
96
74
  when value != nil
97
75
  self[key] = value
@@ -2,10 +2,27 @@ require 'rbconfig'
2
2
 
3
3
  module Nugrant
4
4
  class Config
5
+ DEFAULT_ARRAY_MERGE_STRATEGY = :replace
5
6
  DEFAULT_PARAMS_FILENAME = ".nuparams"
6
7
  DEFAULT_PARAMS_FORMAT = :yaml
7
8
 
8
- attr_reader :params_filename, :params_format, :current_path, :user_path, :system_path
9
+ SUPPORTED_ARRAY_MERGE_STRATEGIES = [:concat, :extend, :replace]
10
+ SUPPORTED_PARAMS_FORMATS = [:json, :yaml]
11
+
12
+ attr_reader :params_filename, :params_format,
13
+ :current_path, :user_path, :system_path,
14
+ :array_merge_strategy,
15
+ :key_error, :parse_error
16
+
17
+ attr_writer :array_merge_strategy
18
+
19
+ ##
20
+ # Convenience method to easily accept either a hash that will
21
+ # be converted to a Nugrant::Config object or directly a config
22
+ # object.
23
+ def self.convert(config = {})
24
+ return config.kind_of?(Nugrant::Config) ? config : Nugrant::Config.new(config)
25
+ end
9
26
 
10
27
  ##
11
28
  # Return the fully expanded path of the user parameters
@@ -27,6 +44,14 @@ module Nugrant
27
44
  "/etc"
28
45
  end
29
46
 
47
+ def self.supported_array_merge_strategy(strategy)
48
+ SUPPORTED_ARRAY_MERGE_STRATEGIES.include?(strategy)
49
+ end
50
+
51
+ def self.supported_params_format(format)
52
+ SUPPORTED_PARAMS_FORMATS.include?(format)
53
+ end
54
+
30
55
  ##
31
56
  # Return true if we are currently on a Windows platform.
32
57
  #
@@ -64,18 +89,50 @@ module Nugrant
64
89
  # parameters should resides. The parameters loaded from this
65
90
  # location have the third highest precedence.
66
91
  # Defaults => Default system path depending on OS + @params_filename
92
+ # * +:array_merge_strategy+ - This option controls how array values are merged together when merging
93
+ # two Bag instances. Possible values are:
94
+ # * :replace => Replace current values by new ones
95
+ # * :extend => Merge current values with new ones
96
+ # * :concat => Append new values to current ones
97
+ # Defaults => The strategy :replace.
98
+ # * +:key_error+ - A callback method receiving one argument, the key as a symbol, and that
99
+ # deal with the error. If the callable does not
100
+ # raise an exception, the result of it's execution is returned.
101
+ # Defaults => A callable that throws a KeyError exception.
102
+ # * +:parse_error+ - A callback method receiving two arguments, the offending filename and
103
+ # the error object, that deal with the error. If the callable does not
104
+ # raise an exception, the result of it's execution is returned.
105
+ # Defaults => A callable that returns the empty hash.
67
106
  #
68
107
  def initialize(options = {})
69
108
  @params_filename = options[:params_filename] || DEFAULT_PARAMS_FILENAME
70
109
  @params_format = options[:params_format] || DEFAULT_PARAMS_FORMAT
71
110
 
72
- raise ArgumentError,
73
- "Invalid value for :params_format. \
74
- The format [#{@params_format}] is currently not supported." if not [:json, :yaml].include?(@params_format)
75
-
76
111
  @current_path = File.expand_path(options[:current_path] || "./#{@params_filename}")
77
112
  @user_path = File.expand_path(options[:user_path] || "#{Config.default_user_path()}/#{@params_filename}")
78
113
  @system_path = File.expand_path(options[:system_path] || "#{Config.default_system_path()}/#{@params_filename}")
114
+
115
+ @array_merge_strategy = options[:array_merge_strategy] || :replace
116
+
117
+ @key_error = options[:key_error] || Proc.new do |key|
118
+ raise KeyError, "Undefined parameter '#{key}'"
119
+ end
120
+
121
+ @parse_error = options[:parse_error] || Proc.new do |filename, error|
122
+ {}
123
+ end
124
+
125
+ validate()
126
+ end
127
+
128
+ def validate()
129
+ raise ArgumentError,
130
+ "Invalid value for :params_format. \
131
+ The format [#{@params_format}] is currently not supported." if not Config.supported_params_format(@params_format)
132
+
133
+ raise ArgumentError,
134
+ "Invalid value for :array_merge_strategy. \
135
+ The array merge strategy [#{@array_merge_strategy}] is currently not supported." if not Config.supported_array_merge_strategy(@array_merge_strategy)
79
136
  end
80
137
  end
81
138
  end
@@ -6,26 +6,24 @@ require 'nugrant/bag'
6
6
  module Nugrant
7
7
  module Helper
8
8
  module Bag
9
- def self.read(filepath, filetype, options = {})
10
- data = parse_data(filepath, filetype, options)
11
-
12
- return Nugrant::Bag.new(data, options)
9
+ def self.read(filepath, filetype, config)
10
+ Nugrant::Bag.new(parse_data(filepath, filetype, config), config)
13
11
  end
14
12
 
15
13
  def self.restricted_keys()
16
14
  Nugrant::Bag.instance_methods()
17
15
  end
18
16
 
19
- def self.parse_data(filepath, filetype, options = {})
17
+ private
18
+
19
+ def self.parse_data(filepath, filetype, config)
20
20
  return if not File.exists?(filepath)
21
21
 
22
22
  File.open(filepath, "rb") do |file|
23
23
  return send("parse_#{filetype}", file)
24
24
  end
25
25
  rescue => error
26
- if options[:error_handler]
27
- options[:error_handler].handle("Could not parse the user #{filetype} parameters file '#{filepath}': #{error}")
28
- end
26
+ config.parse_error.call(filepath, error)
29
27
  end
30
28
 
31
29
  def self.parse_json(io)
@@ -29,6 +29,19 @@ module Nugrant
29
29
  @__defaults
30
30
  end
31
31
 
32
+ def array_merge_strategy
33
+ @__config.array_merge_strategy
34
+ end
35
+
36
+ def array_merge_strategy=(strategy)
37
+ return if not Nugrant::Config.supported_array_merge_strategy(strategy)
38
+
39
+ @__config.array_merge_strategy = strategy
40
+
41
+ # When array_merge_strategy change, we need to recompute parameters hierarchy
42
+ compute_all!()
43
+ end
44
+
32
45
  ##
33
46
  # Set the new default values for the
34
47
  # various parameters contain by this instance.
@@ -39,46 +52,44 @@ module Nugrant
39
52
  # * +elements+ - The new default elements
40
53
  #
41
54
  def defaults=(elements)
42
- @__defaults = Bag.new(elements, @__options)
55
+ @__defaults = Bag.new(elements, @__config)
43
56
 
44
57
  # When defaults change, we need to recompute parameters hierarchy
45
- compute_all!(@__options)
58
+ compute_all!()
46
59
  end
47
60
 
48
61
  ##
49
- # Compute all parameters bags (current, user, system, default and all).
62
+ # Setup instance variables of the mixin. It will compute all parameters bags
63
+ # (current, user, system, default and all) and stored them to these respective
64
+ # instance variables:
50
65
  #
51
- # =| Arguments
52
- # * `config`
53
- # The configuration object used to determine where to find the various
54
- # bag source data. This can be either directly a `Nugrant::Config`
55
- # object or a hash that will be pass to `Nugrant::Config` constructor.
56
- #
57
- # * `options`
58
- # An options hash where some customization option can be passed.
59
- # Defaults to an empty hash, see options for specific option default
60
- # values.
66
+ # * @__current
67
+ # * @__user
68
+ # * @__system
69
+ # * @__defaults
61
70
  #
62
- # =| Options
63
- # * `:defaults`
71
+ # =| Arguments
72
+ # * `defaults`
64
73
  # A hash that is used as the initial data for the defaults bag. Defaults
65
74
  # to an empty hash.
66
75
  #
67
- # * `:key_error`
68
- # This option is passed to Bag.new constructor in it's options hash. See
69
- # Bag.new for details on this options.
76
+ # * `config`
77
+ # A Nugrant::Config object or hash passed to Nugrant::Config
78
+ # constructor. Used to determine where to find the various
79
+ # bag data sources.
70
80
  #
71
- def compute_bags!(config, options = {})
72
- config = config.kind_of?(Nugrant::Config) ? config : Nugrant::Config.new(config)
73
-
74
- @__options = options
81
+ # Passed to nested structures that require nugrant configuration
82
+ # parameters like the Bag object and Helper::Bag module.
83
+ #
84
+ def setup!(defaults = {}, config = {})
85
+ @__config = Nugrant::Config::convert(config);
75
86
 
76
- @__current = Helper::Bag.read(config.current_path, config.params_format, options)
77
- @__user = Helper::Bag.read(config.user_path, config.params_format, options)
78
- @__system = Helper::Bag.read(config.system_path, config.params_format, options)
79
- @__defaults = Bag.new(options[:defaults] || {}, options)
87
+ @__current = Helper::Bag.read(@__config.current_path, @__config.params_format, @__config)
88
+ @__user = Helper::Bag.read(@__config.user_path, @__config.params_format, @__config)
89
+ @__system = Helper::Bag.read(@__config.system_path, @__config.params_format, @__config)
90
+ @__defaults = Bag.new(defaults, @__config)
80
91
 
81
- compute_all!(options)
92
+ compute_all!()
82
93
  end
83
94
 
84
95
  ##
@@ -86,8 +97,8 @@ module Nugrant
86
97
  # bag in the right order and return the result as a Nugrant::Bag
87
98
  # object.
88
99
  #
89
- def compute_all!(options = {})
90
- @__all = Bag.new({}, options)
100
+ def compute_all!()
101
+ @__all = Bag.new({}, @__config)
91
102
  @__all.merge!(@__defaults)
92
103
  @__all.merge!(@__system)
93
104
  @__all.merge!(@__user)
@@ -15,17 +15,11 @@ module Nugrant
15
15
  #
16
16
  # =| Arguments
17
17
  # * `config`
18
- # A hash that will be passed to Nugrant::Config.new() or
19
- # a Nugrant::Config instance directly.
20
- # See Nugrant::Config constructor for options that you can use.
18
+ # Passed to Mixin::Parameters setup! method. See method
19
+ # for further information.
21
20
  #
22
- # * `options`
23
- # An options hash that is passed to Mixin::Parameters.compute_bags! method.
24
- # See Mixin::Parameters.compute_bags! for details on the various options
25
- # available.
26
- #
27
- def initialize(config, options = {})
28
- compute_bags!(config, options)
21
+ def initialize(config)
22
+ setup!({}, config)
29
23
  end
30
24
 
31
25
  include Mixin::Parameters
@@ -7,6 +7,12 @@ module Nugrant
7
7
  module Errors
8
8
  class NugrantVagrantError < ::Vagrant::Errors::VagrantError
9
9
  error_namespace("nugrant.vagrant.errors")
10
+
11
+ def compute_context()
12
+ Helper::Stack.fetch_error_region(caller(), {
13
+ :matcher => /(.+Vagrantfile):([0-9]+)/
14
+ })
15
+ end
10
16
  end
11
17
 
12
18
  class ParameterNotFoundError < NugrantVagrantError
@@ -15,11 +21,13 @@ module Nugrant
15
21
  def initialize(options = nil, *args)
16
22
  super({:context => compute_context()}.merge(options || {}), *args)
17
23
  end
24
+ end
18
25
 
19
- def compute_context()
20
- Helper::Stack.fetch_error_region(caller(), {
21
- :matcher => /(.+Vagrantfile):([0-9]+)/
22
- })
26
+ class VagrantUserParseError < NugrantVagrantError
27
+ error_key(:parse_error)
28
+
29
+ def initialize(options = nil, *args)
30
+ super(options, *args)
23
31
  end
24
32
  end
25
33
  end
@@ -10,11 +10,15 @@ module Nugrant
10
10
  attr_reader :__current, :__user, :__system, :__defaults, :__all
11
11
 
12
12
  def initialize()
13
- compute_bags!({:params_filename => ".vagrantuser"}, options = {
13
+ setup!({},
14
+ :params_filename => ".vagrantuser",
14
15
  :key_error => Proc.new do |key|
15
16
  raise Errors::ParameterNotFoundError, :key => key.to_s
17
+ end,
18
+ :parse_error => Proc.new do |filename, error|
19
+ raise Errors::VagrantUserParseError, :filename => filename.to_s, :error => error
16
20
  end
17
- })
21
+ )
18
22
  end
19
23
 
20
24
  include Mixin::Parameters
@@ -1,3 +1,3 @@
1
1
  module Nugrant
2
- VERSION = "2.0.0.pre1"
2
+ VERSION = "2.0.0.pre2"
3
3
  end
data/locales/en.yml CHANGED
@@ -11,3 +11,14 @@ en:
11
11
 
12
12
  If you think it should be found, don't hesitate to fill an
13
13
  issue @ https://github.com/maoueh/nugrant/issues.
14
+
15
+ parse_error: |-
16
+ Nugrant: Vagrant user file could not be parsed correctly,
17
+ the file is probably in an invalid state.
18
+
19
+ File: %{filename}
20
+ Error: %{error}
21
+
22
+ If you think this is an error, don't hesitate to fill an
23
+ issue @ https://github.com/maoueh/nugrant/issues.
24
+
@@ -131,33 +131,33 @@ module Nugrant
131
131
  end
132
132
 
133
133
  def test_merge_array_extend()
134
- bag1 = create_bag({"first" => [1, 2]})
134
+ bag1 = create_bag({"first" => [1, 2]}, :array_merge_strategy => :extend)
135
135
  bag2 = create_bag({:first => [2, 3]})
136
136
 
137
- bag1.merge!(bag2, :array_strategy => :extend);
137
+ bag1.merge!(bag2);
138
138
 
139
139
  assert_equal({:first => [1, 2, 3]}, bag1.to_hash())
140
140
 
141
- bag1 = create_bag({"first" => [1, 2]})
141
+ bag1 = create_bag({"first" => [1, 2]}, :array_merge_strategy => :extend)
142
142
  bag2 = create_bag({:first => "string"})
143
143
 
144
- bag1.merge!(bag2, :array_strategy => :extend);
144
+ bag1.merge!(bag2);
145
145
 
146
146
  assert_equal({:first => "string"}, bag1.to_hash())
147
147
  end
148
148
 
149
149
  def test_merge_array_concat()
150
- bag1 = create_bag({"first" => [1, 2]})
150
+ bag1 = create_bag({"first" => [1, 2]}, :array_merge_strategy => :concat)
151
151
  bag2 = create_bag({:first => [2, 3]})
152
152
 
153
- bag1.merge!(bag2, :array_strategy => :concat);
153
+ bag1.merge!(bag2);
154
154
 
155
155
  assert_equal({:first => [1, 2, 2, 3]}, bag1.to_hash())
156
156
 
157
- bag1 = create_bag({"first" => [1, 2]})
157
+ bag1 = create_bag({"first" => [1, 2]}, :array_merge_strategy => :concat)
158
158
  bag2 = create_bag({:first => "string"})
159
159
 
160
- bag1.merge!(bag2, :array_strategy => :concat);
160
+ bag1.merge!(bag2);
161
161
 
162
162
  assert_equal({:first => "string"}, bag1.to_hash())
163
163
  end
@@ -1,7 +1,7 @@
1
1
  This readme give information on how to read resources file
2
2
  that test merge possibilities.
3
3
 
4
- Naming convetions
4
+ Naming conventions
5
5
  -----------------
6
6
 
7
7
  The filename uses a specific convention:
@@ -9,7 +9,7 @@ The filename uses a specific convention:
9
9
  params_*kind*_*level*.[yml|json]
10
10
 
11
11
  The kind is one of: [`current`|`user`|`system`] and defines which
12
- responsability they will hold. The order is `current` overrides
12
+ responsibility they will hold. The order is `current` overrides
13
13
  `user` overrides `system`.
14
14
 
15
15
  Inside file, keys have special meaning. They define how
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nugrant
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.pre1
4
+ version: 2.0.0.pre2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthieu Vachon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-18 00:00:00.000000000 Z
11
+ date: 2014-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: insensitive_hash