nxt_init 0.1.4 → 0.1.5

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
  SHA256:
3
- metadata.gz: 2e0d3388fecb1cea6337c51e9099379ea524e5d3721177be48c5d2f24777530e
4
- data.tar.gz: 43d916b6c32b952f397d16fe4cf45e4459a1fd8edcbc45a14aa3dc79810e7b4c
3
+ metadata.gz: e476a1496d78ec53eff95f0d9c1ac56938adbd21ff3773ead35cd75142f9e80b
4
+ data.tar.gz: e4c28f04b5f4bae9b18e63207af4769c312431ec622bbbdf3a3d8c0df9a68a47
5
5
  SHA512:
6
- metadata.gz: 957b15225b7d1f6a86afae921194555f2a59a40b3d84f1af2c1c3eca1ddf6c18522ab8f85a8ce64051c74abf69108abe218c672acb63ae504c4c9ee393577a4f
7
- data.tar.gz: d778870ebbb87532d8696c29668263b143dfd6fc345aad36f01e8644034229ef625a4a73f2e23c270a0d7cb81dccde02dd634f8c138b1ce3f9f0dd855701d24c
6
+ metadata.gz: 53b5060fe7b794a93c28a0cbee74b5192d4355d1d140330990cd3d88e4574da795dc44d7018cbd0f3095c6970f5a7e231348f19bad48c4c25465492162921cec
7
+ data.tar.gz: 7f8a523bda1983ace6c0920c41e4f5bbfff06efee3225320c86c9a232c6d404034e91fab98d1d05ff5c4de16a70a31374b47ebb7f044454f4f1bda353999790d
@@ -0,0 +1,52 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2
6
+ jobs:
7
+ build:
8
+ docker:
9
+ # specify the version you desire here
10
+ - image: circleci/ruby:2.6.1-node
11
+
12
+ working_directory: ~/repo
13
+
14
+ steps:
15
+ - checkout
16
+
17
+ # Download and cache dependencies
18
+ - restore_cache:
19
+ keys:
20
+ - v1-dependencies-{{ checksum "Gemfile.lock" }}
21
+
22
+ - run:
23
+ name: install dependencies
24
+ command: |
25
+ bundle install --jobs=4 --retry=3 --path vendor/bundle
26
+
27
+ - save_cache:
28
+ paths:
29
+ - ./vendor/bundle
30
+ key: v1-dependencies-{{ checksum "Gemfile.lock" }}
31
+
32
+ # run tests!
33
+ - run:
34
+ name: run tests
35
+ command: |
36
+ mkdir /tmp/test-results
37
+ TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
38
+ circleci tests split --split-by=timings)"
39
+
40
+ bundle exec rspec \
41
+ --format progress \
42
+ --format RspecJunitFormatter \
43
+ --out /tmp/test-results/rspec.xml \
44
+ --format progress \
45
+ $TEST_FILES
46
+
47
+ # collect reports
48
+ - store_test_results:
49
+ path: /tmp/test-results
50
+ - store_artifacts:
51
+ path: /tmp/test-results
52
+ destination: test-results
@@ -1 +1 @@
1
- 2.6.1
1
+ 2.6.3
data/Gemfile CHANGED
@@ -4,3 +4,7 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in nxt_init.gemspec
6
6
  gemspec
7
+
8
+ group :test do
9
+ gem 'rspec_junit_formatter' # for CircleCI
10
+ end
@@ -1,41 +1,43 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nxt_init (0.1.2)
4
+ nxt_init (0.1.5)
5
5
  activesupport
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (5.2.2)
10
+ activesupport (5.2.3)
11
11
  concurrent-ruby (~> 1.0, >= 1.0.2)
12
12
  i18n (>= 0.7, < 2)
13
13
  minitest (~> 5.1)
14
14
  tzinfo (~> 1.1)
15
15
  coderay (1.1.2)
16
- concurrent-ruby (1.1.4)
16
+ concurrent-ruby (1.1.5)
17
17
  diff-lcs (1.3)
18
- i18n (1.5.3)
18
+ i18n (1.6.0)
19
19
  concurrent-ruby (~> 1.0)
20
20
  method_source (0.9.2)
21
21
  minitest (5.11.3)
22
22
  pry (0.12.2)
23
23
  coderay (~> 1.1.0)
24
24
  method_source (~> 0.9.0)
25
- rake (10.5.0)
25
+ rake (12.3.2)
26
26
  rspec (3.8.0)
27
27
  rspec-core (~> 3.8.0)
28
28
  rspec-expectations (~> 3.8.0)
29
29
  rspec-mocks (~> 3.8.0)
30
- rspec-core (3.8.0)
30
+ rspec-core (3.8.2)
31
31
  rspec-support (~> 3.8.0)
32
- rspec-expectations (3.8.2)
32
+ rspec-expectations (3.8.4)
33
33
  diff-lcs (>= 1.2.0, < 2.0)
34
34
  rspec-support (~> 3.8.0)
35
- rspec-mocks (3.8.0)
35
+ rspec-mocks (3.8.1)
36
36
  diff-lcs (>= 1.2.0, < 2.0)
37
37
  rspec-support (~> 3.8.0)
38
- rspec-support (3.8.0)
38
+ rspec-support (3.8.2)
39
+ rspec_junit_formatter (0.4.1)
40
+ rspec-core (>= 2, < 4, != 2.12.0)
39
41
  thread_safe (0.3.6)
40
42
  tzinfo (1.2.5)
41
43
  thread_safe (~> 0.1)
@@ -47,8 +49,9 @@ DEPENDENCIES
47
49
  bundler (~> 1.17)
48
50
  nxt_init!
49
51
  pry
50
- rake (~> 10.0)
52
+ rake (~> 12.3)
51
53
  rspec (~> 3.0)
54
+ rspec_junit_formatter
52
55
 
53
56
  BUNDLED WITH
54
57
  1.17.2
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![CircleCI](https://circleci.com/gh/nxt-insurance/nxt_init.svg?style=svg)](https://circleci.com/gh/nxt-insurance/nxt_init)
2
+
1
3
  # NxtInit
2
4
 
3
5
  Create an initializer that accepts option arguments and define private readers for your
@@ -21,39 +23,72 @@ Or install it yourself as:
21
23
 
22
24
  ## Usage
23
25
 
26
+ NxtInit removes some boilerplate. Instead of writing your initializer and (private) attribute readers each and every time like so:
27
+
24
28
  ```ruby
25
- class MyService
26
- include NxtInit
27
- attr_init :one,
28
- two: 'has a default',
29
- three: nil, # makes the attribute optional
30
- four: -> { "This is set on initialize: #{Time.now} - means it will not be evaluated multiple times" }
31
-
32
- def call
33
- {
34
- one: one,
35
- two: two,
36
- three: three,
37
- four: four
38
- }
39
- end
29
+ class GetSafe
30
+ def initialize(frontend:, backend:)
31
+ @frontend = frontend
32
+ @backend = backend
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :frontend, :backend
40
38
  end
39
+ ```
41
40
 
42
- my_service = MyService.new(one: 'this is required')
43
- my_service.call
41
+ You can instead do the following:
44
42
 
45
- # Will output the following:
46
- {
43
+ ```ruby
44
+ class GetSafe
45
+ include NxtInit
46
+ attr_init :frontend, :backend
47
+ end
47
48
 
48
- one: "this is required",
49
- two: "has a default",
50
- three: nil,
51
- four: "This is evaluated on initialize: 2019-02-04 18:10:56 +0100 - means it will not be evaluated multiple times"
52
- }
49
+ GetSafe.new # KeyError (NxtInit attr_init key :frontend was missing at initialization!
50
+ GetSafe.new(frontend: 'React', backend: 'Ruby on Rails') #<GetSafe:0x00007f81fb8506b8 @frontend="React", @backend="Ruby on Rails">
53
51
  ```
54
52
 
55
- The attribute readers are private. If you need public accessors you have to add them yourself. That's all there is.
56
- Check out the specs for examples how we handle inheritance.
53
+ ### Optional arguments and defaults
54
+
55
+ In order to provide default values you can simply use the hash syntax to define your defaults.
56
+ If you want to make an attribute optional, just pass nil as the default argument.
57
+ If there is no default value and you did not provide one when initializing your class, you will get a KeyError.
58
+
59
+ ```ruby
60
+ class GetSafe
61
+ include NxtInit
62
+ attr_init frontend: 'React',
63
+ backend: -> { 'Ruby on Rails' },
64
+ middleware: nil
65
+ end
66
+
67
+ GetSafe.new #<GetSafe:0x00007fab608e1918 @frontend="React", @backend="Ruby on Rails", @middleware=nil>
68
+ ```
69
+
70
+ ### Preprocessors
71
+
72
+ If you want to preprocess your attribute somehow, you can define a preprocessor block to which the original attribute will be yielded.
73
+ Note that you can also call methods in your block if you have some heavier lifting to do.
74
+
75
+ ```ruby
76
+ class GetSafe
77
+ include NxtInit
78
+ attr_init date: -> (date) { date && (date.is_a?(Date) ? date : Date.parse(date)) }
79
+ end
80
+
81
+ GetSafe.new(date: '2020/12/12').send(:date) # will give you the date
82
+ GetSafe.new(date: nil).send(:date) # would give you nil
83
+ GetSafe.new # would raise KeyError (NxtInit attr_init key :date was missing at initialization!)
84
+ ```
85
+
86
+ Also you can still pass in nil if your block can handle it. If the attribute is not provided on initialization again a KeyError will be raised.
87
+
88
+ ### Inheritance
89
+
90
+ When you inherit from a class that already includes NxtInit you can add further attributes to your subclass and overwrite existing options
91
+ simply by using attr_init for the same attributes. Check out the specs for more examples.
57
92
 
58
93
  ## Development
59
94
 
@@ -1,15 +1,17 @@
1
1
  require "nxt_init/version"
2
- require 'active_support'
2
+ require "nxt_init/option"
3
+ require "nxt_init/not_provided_option"
4
+ require 'active_support/all'
3
5
 
4
6
  module NxtInit
5
- InvalidOptionError = Class.new(ArgumentError)
6
-
7
7
  module ClassMethods
8
8
  def attr_init(*args)
9
- flat_args = flatten_options(*args)
10
- self.attr_init_opts ||= []
11
- self.attr_init_opts += flat_args
12
- define_private_readers(*flat_args)
9
+ options_map = build_options_map(*args)
10
+
11
+ self.attr_init_opts ||= {}
12
+ self.attr_init_opts.merge!(options_map)
13
+
14
+ define_private_readers(*options_map.keys)
13
15
  end
14
16
 
15
17
  attr_accessor :attr_init_opts
@@ -17,31 +19,29 @@ module NxtInit
17
19
  private
18
20
 
19
21
  def inherited(subclass)
20
- subclass.attr_init_opts = attr_init_opts.map(&:dup)
22
+ subclass.attr_init_opts = attr_init_opts.deep_dup
21
23
  end
22
24
 
23
- def define_private_readers(*args)
24
- keys = args.map { |attr| attr.is_a?(Hash) ? attr.keys.first : attr }
25
+ def define_private_readers(*keys)
25
26
  attr_reader *keys
26
27
  private *keys
27
28
  end
28
29
 
29
- def flatten_options(*args)
30
+ def build_options_map(*args)
30
31
  options_hash = *args.extract_options!
31
- options_hash.each { |key, value| args << {"#{key}": value} }
32
- args
32
+ options_from_args = args.each_with_object({}) { |key, acc| acc[key] = Option.new(key) }
33
+ options_from_options = options_hash.each_with_object({}) { |(key, value), acc| acc[key] = Option.new(key, default_value: value) }
34
+ options_from_args.merge(options_from_options)
33
35
  end
34
36
  end
35
37
 
36
38
  module InstanceMethods
37
39
  def initialize(*args, **attrs)
38
- option_keys = self.class.send(:attr_init_opts).map do |option|
39
- option.is_a?(Hash) ? option.keys.first : option
40
- end
40
+ option_keys = self.class.send(:attr_init_opts).keys
41
41
 
42
42
  attr_init_opts = attrs.slice(*option_keys)
43
43
  other_options = attrs.slice!(*option_keys)
44
- # passing **{} is like calling super({}) which does not work when super does not except arguments
44
+ # passing **{} is like calling super({}) which does not work when super does not except arguments#
45
45
  initialize_attrs_from_options(**attr_init_opts)
46
46
  other_options.empty? ? super(*args) : super(*args, **other_options)
47
47
  end
@@ -49,39 +49,11 @@ module NxtInit
49
49
  private
50
50
 
51
51
  def initialize_attrs_from_options(**attrs)
52
- self.class.send(:attr_init_opts).each do |opt|
53
- if opt.is_a?(Hash)
54
- key = opt.keys.first
55
- default_value = opt.values.first
56
- given_value = attrs[key]
57
- key_missing = !attrs.key?(key)
58
-
59
- if default_value_is_preprocessor?(default_value)
60
- value = key_missing ? raise_key_error(key) : instance_exec(given_value, &default_value)
61
- else
62
- value = given_value || (default_value.respond_to?(:call) ? instance_exec(&default_value) : default_value)
63
- end
64
- elsif opt.is_a?(Symbol)
65
- key = opt
66
- value = attrs.fetch(opt) { |k| raise_key_error(k) }
67
- else
68
- raise InvalidOptionError, "Don't know how to deal with #{opt}"
69
- end
70
- instance_variable_set("@#{key}", value)
52
+ self.class.send(:attr_init_opts).each do |_, opt|
53
+ value = opt.resolve(attrs, target: self)
54
+ instance_variable_set("@#{opt.key}", value)
71
55
  end
72
56
  end
73
-
74
- def default_value_is_block?(default_value)
75
- default_value.respond_to?(:call)
76
- end
77
-
78
- def default_value_is_preprocessor?(default_value)
79
- default_value_is_block?(default_value) && default_value.arity == 1
80
- end
81
-
82
- def raise_key_error(key)
83
- raise KeyError, "NxtInit attr_init key :#{key} was missing at initialization!"
84
- end
85
57
  end
86
58
 
87
59
  def self.included(base)
@@ -0,0 +1,4 @@
1
+ module NxtInit
2
+ class NotProvidedOption
3
+ end
4
+ end
@@ -0,0 +1,56 @@
1
+ module NxtInit
2
+ class Option
3
+ InvalidOptionError = Class.new(ArgumentError)
4
+
5
+ def initialize(key, default_value: NotProvidedOption.new)
6
+ @key = key
7
+ @default_value = default_value
8
+ end
9
+
10
+ attr_reader :key, :default_value
11
+
12
+ def resolve(attrs, target:)
13
+ if default_value_was_given?
14
+ key_missing = !attrs.key?(key)
15
+ given_value = attrs[key]
16
+
17
+ if default_value_is_preprocessor?
18
+ key_missing ? raise_key_error : target.instance_exec(given_value, &default_value)
19
+ else
20
+ # only when the given value was nil we will evaluate the fallback --> false is a valid value
21
+ if given_value.nil?
22
+ default_value_is_block? ? target.instance_exec(&default_value) : default_value
23
+ else
24
+ given_value
25
+ end
26
+ end
27
+ elsif requires_value?
28
+ attrs.fetch(key) { |_| raise_key_error }
29
+ else
30
+ raise InvalidOptionError, "Don't know how to deal with #{self}"
31
+ end
32
+ end
33
+
34
+ def requires_value?
35
+ !default_value_was_given?
36
+ end
37
+
38
+ def default_value_is_block?
39
+ default_value && default_value.respond_to?(:call)
40
+ end
41
+
42
+ def default_value_is_preprocessor?
43
+ default_value_is_block? && default_value.arity == 1
44
+ end
45
+
46
+ def default_value_was_given?
47
+ !default_value.is_a?(NotProvidedOption)
48
+ end
49
+
50
+ private
51
+
52
+ def raise_key_error
53
+ raise KeyError, "NxtInit attr_init key :#{key} was missing at initialization!"
54
+ end
55
+ end
56
+ end
@@ -1,3 +1,3 @@
1
1
  module NxtInit
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  spec.add_dependency "activesupport"
38
38
  spec.add_development_dependency "bundler", "~> 1.17"
39
- spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "rake", "~> 12.3"
40
40
  spec.add_development_dependency "pry"
41
41
  spec.add_development_dependency "rspec", "~> 3.0"
42
42
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nxt_init
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Robecke
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2019-02-26 00:00:00.000000000 Z
13
+ date: 2019-07-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -46,14 +46,14 @@ dependencies:
46
46
  requirements:
47
47
  - - "~>"
48
48
  - !ruby/object:Gem::Version
49
- version: '10.0'
49
+ version: '12.3'
50
50
  type: :development
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
53
53
  requirements:
54
54
  - - "~>"
55
55
  - !ruby/object:Gem::Version
56
- version: '10.0'
56
+ version: '12.3'
57
57
  - !ruby/object:Gem::Dependency
58
58
  name: pry
59
59
  requirement: !ruby/object:Gem::Requirement
@@ -89,6 +89,7 @@ executables: []
89
89
  extensions: []
90
90
  extra_rdoc_files: []
91
91
  files:
92
+ - ".circleci/config.yml"
92
93
  - ".gitignore"
93
94
  - ".rspec"
94
95
  - ".ruby-version"
@@ -101,6 +102,8 @@ files:
101
102
  - bin/console
102
103
  - bin/setup
103
104
  - lib/nxt_init.rb
105
+ - lib/nxt_init/not_provided_option.rb
106
+ - lib/nxt_init/option.rb
104
107
  - lib/nxt_init/version.rb
105
108
  - nxt_init.gemspec
106
109
  homepage: https://github.com/nxt-insurance
@@ -125,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
128
  - !ruby/object:Gem::Version
126
129
  version: '0'
127
130
  requirements: []
128
- rubygems_version: 3.0.1
131
+ rubygems_version: 3.0.3
129
132
  signing_key:
130
133
  specification_version: 4
131
134
  summary: nxt_init allows you to define an initializer that takes option arguments