nxt_init 0.1.4 → 0.1.5

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
  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