ks 0.0.1 → 0.0.2

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: f36c29feda7f2d5ef40f578461982bfc9d1b19d3
4
- data.tar.gz: 1b15cad80b3bdfa52af0f482096c0eae77836c0b
3
+ metadata.gz: 6ac4b409cd2da70b14d2bd80734bcec3cbb69e3a
4
+ data.tar.gz: 8766f1ce550dd060e7cc27997974f1a4eecdd846
5
5
  SHA512:
6
- metadata.gz: bc92b6fc8685faea432f14c1953e2191fa963231bd2260966b49d9849198b43b333717fad75ac870a334764cfcba3cf0d0ac0f4a0cc9618fd67b4410c5c0de87
7
- data.tar.gz: 20768fa163981bc152fdd424a7946e7709e4bbe6344ba3a9a3969a3195d0937ba8d8837a142a2ca8e234750e5c6780f69e1426df0bea9d096574cdbc3aab2bad
6
+ metadata.gz: c5fd595264b15cb35fa9d6ef0b6269c7ca79910df4cc65d02fd73e53a7c7180a2b5b6cf91bce83de035f9e15fabc48bf73b73c4ee935de9315fb01d943804244
7
+ data.tar.gz: a15d78f2e7340bb1013152b7146832eb2fd30e51c5b98f357be1dcbe1c1c6bc74210cd7d4cbb22c3b3228e3fec930dbdbc292052d96e5c0a1c4caa4d7ee28177
@@ -0,0 +1,50 @@
1
+ # rcov generated
2
+ coverage
3
+ coverage.data
4
+
5
+ # rdoc generated
6
+ rdoc
7
+
8
+ # yard generated
9
+ doc
10
+ .yardoc
11
+
12
+ # bundler
13
+ .bundle
14
+ Gemfile.lock
15
+
16
+ # jeweler generated
17
+ pkg
18
+
19
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
20
+ #
21
+ # * Create a file at ~/.gitignore
22
+ # * Include files you want ignored
23
+ # * Run: git config --global core.excludesfile ~/.gitignore
24
+ #
25
+ # After doing this, these files will be ignored in all your git projects,
26
+ # saving you from having to 'pollute' every project you touch with them
27
+ #
28
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
29
+ #
30
+ # For MacOS:
31
+ #
32
+ #.DS_Store
33
+
34
+ # For TextMate
35
+ #*.tmproj
36
+ #tmtags
37
+
38
+ # For emacs:
39
+ #*~
40
+ #\#*
41
+ #.\#*
42
+
43
+ # For vim:
44
+ #*.swp
45
+
46
+ # For redcar:
47
+ #.redcar
48
+
49
+ # For rubinius:
50
+ #*.rbc
@@ -0,0 +1,10 @@
1
+ inherit_gem:
2
+ wetransfer_style: ruby/default.yml
3
+ Layout/FirstMethodArgumentLineBreak:
4
+ Enabled: false
5
+ Layout/FirstMethodParameterLineBreak:
6
+ Enabled: false
7
+ Style/GlobalVars:
8
+ Exclude:
9
+ - qa/*.rb
10
+ - spec/spec_helper.rb
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 2.1.5
3
+ - 2.2.2
4
+ sudo: false
5
+ cache: bundler
data/Gemfile CHANGED
@@ -1,8 +1,5 @@
1
- source "http://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- group :development do
4
- gem "rspec", "~> 3.2.0"
5
- gem "rdoc", "~> 3.12"
6
- gem "bundler", "~> 1.0"
7
- gem "jeweler", "~> 2.0.1"
8
- end
3
+ source 'http://rubygems.org'
4
+
5
+ gemspec
data/Rakefile CHANGED
@@ -1,51 +1,18 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- require 'rubygems'
4
- require 'bundler'
5
- begin
6
- Bundler.setup(:default, :development)
7
- rescue Bundler::BundlerError => e
8
- $stderr.puts e.message
9
- $stderr.puts "Run `bundle install` to install missing gems"
10
- exit e.status_code
11
- end
12
- require 'rake'
13
-
14
- require_relative 'lib/ks'
15
- require 'jeweler'
16
- Jeweler::Tasks.new do |gem|
17
- gem.version = Ks::VERSION
18
- gem.name = "ks"
19
- gem.homepage = "http://github.com/wetransfer/ks"
20
- gem.license = "MIT"
21
- gem.description = %Q{Keyword-initialized Structs}
22
- gem.description = %Q{Keyword-initialized Structs}
23
- gem.email = "me@julik.nl"
24
- gem.authors = ["Julik Tarkhanov"]
25
- # dependencies defined in Gemfile
26
- end
27
- Jeweler::RubygemsDotOrgTasks.new
28
-
29
- require 'rspec/core'
3
+ require 'bundler/gem_tasks'
30
4
  require 'rspec/core/rake_task'
31
- RSpec::Core::RakeTask.new(:spec) do |spec|
32
- spec.pattern = FileList['spec/**/*_spec.rb']
33
- end
5
+ require 'yard'
6
+ require 'rubocop/rake_task'
34
7
 
35
- desc "Code coverage detail"
36
- task :simplecov do
37
- ENV['COVERAGE'] = "true"
38
- Rake::Task['spec'].execute
8
+ YARD::Rake::YardocTask.new(:doc) do |t|
9
+ # The dash has to be between the two to "divide" the source files and
10
+ # miscellaneous documentation files that contain no code
11
+ t.files = ['lib/**/*.rb', '-', 'LICENSE.txt', 'IMPLEMENTATION_DETAILS.md']
39
12
  end
40
13
 
41
- task :default => :spec
14
+ RSpec::Core::RakeTask.new(:spec)
42
15
 
43
- require 'rdoc/task'
44
- Rake::RDocTask.new do |rdoc|
45
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
16
+ RuboCop::RakeTask.new(:rubocop)
46
17
 
47
- rdoc.rdoc_dir = 'rdoc'
48
- rdoc.title = "ks #{version}"
49
- rdoc.rdoc_files.include('README*')
50
- rdoc.rdoc_files.include('lib/**/*.rb')
51
- end
18
+ task default: %i[spec rubocop]
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'ks'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'ks'
9
+ spec.version = Ks::VERSION
10
+ spec.authors = ['Julik Tarkhanov']
11
+ spec.email = ['me@julik.nl']
12
+
13
+ spec.summary = 'Keyword-initialized Structs'
14
+ spec.description = 'Keyword-initialized Structs'
15
+ spec.homepage = 'http://github.com/WeTransfer/ks'
16
+
17
+ # Prevent pushing this gem to RubyGems.org.
18
+ # To allow pushes either set the 'allowed_push_host'
19
+ # To allow pushing to a single host or delete
20
+ # this section to allow pushing to any host.
21
+ if spec.respond_to?(:metadata)
22
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
23
+ else
24
+ raise 'RubyGems 2.0 or newer is required to protect against ' \
25
+ 'public gem pushes.'
26
+ end
27
+
28
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
29
+ f.match(%r{^(test|spec|features)/})
30
+ end
31
+ spec.bindir = 'exe'
32
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
+ spec.require_paths = ['lib']
34
+
35
+ spec.add_development_dependency 'bundler', '~> 1'
36
+ spec.add_development_dependency 'rake', '~> 12'
37
+ spec.add_development_dependency 'rspec', '~> 3'
38
+ spec.add_development_dependency 'wetransfer_style', '0.6.0'
39
+ spec.add_development_dependency 'yard', '~> 0.9'
40
+ end
data/lib/ks.rb CHANGED
@@ -1,13 +1,14 @@
1
- require 'thread'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'set'
3
4
 
4
5
  # "Ks" - as in "kiss" - a generator of keyworded Structs.
5
6
  module Ks
6
- VERSION = '0.0.1'
7
-
7
+ VERSION = '0.0.2'
8
+
8
9
  @@caching_mutex = Mutex.new
9
10
  @@predefined_structs = {}
10
-
11
+
11
12
  # Returns a class that is a descendant of Struct, with a strict
12
13
  # keyword initializer.
13
14
  #
@@ -17,9 +18,10 @@ module Ks
17
18
  # Note that all the keyword arguments defined for the class (all the members)
18
19
  # are going to be required keyword arguments for the initializer.
19
20
  #
20
- # The created classes (Struct descendants) are cached to make reloading easier,
21
- # since when reloading a usual Struct descendant it will receive a different parent
22
- # class. This is mitigated by caching the created subclasses using their member lists
21
+ # The created classes (Struct descendants) are cached
22
+ # to make reloading easier, since when reloading a usual Struct
23
+ # descendant it will receive a different parent class.
24
+ # This is mitigated by caching the created subclasses using their member lists
23
25
  #
24
26
  # @param members[Array<Symbol>] the names of members to create
25
27
  # @return created_class[Class]
@@ -27,7 +29,7 @@ module Ks
27
29
  k = members.sort.join(':')
28
30
  @@caching_mutex.synchronize do
29
31
  return @@predefined_structs[k] if @@predefined_structs[k]
30
-
32
+
31
33
  struct_ancestor = Struct.new(*members)
32
34
  predefined = Class.new(struct_ancestor) do
33
35
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
@@ -40,4 +42,49 @@ module Ks
40
42
  predefined
41
43
  end
42
44
  end
45
+
46
+ # Returns a class that is a descendant of Struct, with a
47
+ # keyword initializer that permits unknown keywords to be passed in.
48
+ # Those keywords will be dropped. The keywords that are known at
49
+ # definition time will be checked for presence. This allows you to
50
+ # use structs for API responses and payloads that might get additional
51
+ # properties as the API evolves, without breaking (your) consuming
52
+ # code. Imagine at time of designing your structures you specify a
53
+ # Shipment:
54
+ #
55
+ # Shipment = Ks.allowing_unknown(:sku, :weight)
56
+ #
57
+ # The API you are using, however, later adds a "shipping_company_id"
58
+ # property. If you had used `strict` your struct would fail to initialize,
59
+ # since it does not know about the `shipping_company_id` attribute.
60
+ #
61
+ # Shipment.new(JSON.parse(payload)) #=> ArgumentError...
62
+ #
63
+ # but as you have used `allowing_unknown` the "shipping_company_id" property
64
+ # will be silently dropped instead.
65
+ #
66
+ # The created classes (Struct descendants) are cached
67
+ # to make reloading easier, since when reloading a usual Struct
68
+ # descendant it will receive a different parent class.
69
+ # This is mitigated by caching the created subclasses using their member lists
70
+ #
71
+ # @param members[Array<Symbol>] the names of members to create. Those members will be required, just like with `Ks.strict`
72
+ # @return created_class[Class]
73
+ def self.allowing_unknown(*members)
74
+ k = 'with_optionals:' + members.sort.join(':')
75
+ @@caching_mutex.synchronize do
76
+ return @@predefined_structs[k] if @@predefined_structs[k]
77
+
78
+ struct_ancestor = Struct.new(*members)
79
+ predefined = Class.new(struct_ancestor) do
80
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
81
+ def initialize(#{members.map { |a| "#{a}:" }.join(', ')}, **) # def initialize(bar:, baz:, **)
82
+ super(#{members.join(', ')}) # super(bar, baz)
83
+ end # end
84
+ METHOD
85
+ end
86
+ @@predefined_structs[k] = predefined
87
+ predefined
88
+ end
89
+ end
43
90
  end
metadata CHANGED
@@ -1,92 +1,107 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julik Tarkhanov
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2015-11-09 00:00:00.000000000 Z
11
+ date: 2019-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rspec
14
+ name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 3.2.0
19
+ version: '1'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 3.2.0
26
+ version: '1'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rdoc
28
+ name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.12'
33
+ version: '12'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.12'
40
+ version: '12'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.0'
47
+ version: '3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.0'
54
+ version: '3'
55
55
  - !ruby/object:Gem::Dependency
56
- name: jeweler
56
+ name: wetransfer_style
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.6.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.6.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: 2.0.1
75
+ version: '0.9'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: 2.0.1
82
+ version: '0.9'
69
83
  description: Keyword-initialized Structs
70
- email: me@julik.nl
84
+ email:
85
+ - me@julik.nl
71
86
  executables: []
72
87
  extensions: []
73
- extra_rdoc_files:
74
- - LICENSE.txt
75
- - README.md
88
+ extra_rdoc_files: []
76
89
  files:
77
90
  - ".document"
91
+ - ".gitignore"
78
92
  - ".rspec"
93
+ - ".rubocop.yml"
94
+ - ".travis.yml"
79
95
  - Gemfile
80
96
  - LICENSE.txt
81
97
  - README.md
82
98
  - Rakefile
99
+ - ks.gemspec
83
100
  - lib/ks.rb
84
- - spec/ks_spec.rb
85
- - spec/spec_helper.rb
86
- homepage: http://github.com/wetransfer/ks
87
- licenses:
88
- - MIT
89
- metadata: {}
101
+ homepage: http://github.com/WeTransfer/ks
102
+ licenses: []
103
+ metadata:
104
+ allowed_push_host: https://rubygems.org
90
105
  post_install_message:
91
106
  rdoc_options: []
92
107
  require_paths:
@@ -103,8 +118,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
118
  version: '0'
104
119
  requirements: []
105
120
  rubyforge_project:
106
- rubygems_version: 2.2.2
121
+ rubygems_version: 2.6.11
107
122
  signing_key:
108
123
  specification_version: 4
109
- summary: ''
124
+ summary: Keyword-initialized Structs
110
125
  test_files: []
@@ -1,28 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "Ks" do
4
- describe '.strict' do
5
- it "allocates a Struct class that can be initialized with keywords" do
6
- k = Ks.strict(:foo, :bar)
7
- item = k.new(foo: 1, bar: 2)
8
- expect(item.foo).to eq(1)
9
- expect(item.bar).to eq(2)
10
- expect(item.class.ancestors).to include(Struct)
11
- expect(item.members).to eq([:foo, :bar])
12
- end
13
-
14
- it 'raises when keyword arguments are omitted' do
15
- k = Ks.strict(:foo, :bar)
16
- expect {
17
- k.new(foo: 1)
18
- }.to raise_error(ArgumentError, 'missing keyword: bar')
19
- end
20
-
21
- it 'caches the created Struct ancestor even when using multiple threads' do
22
- classes = (1..12).map do
23
- Thread.new { Ks.strict(:one, :another) }
24
- end.map(&:join).map(&:value)
25
- expect(classes.uniq.length).to eq(1)
26
- end
27
- end
28
- end
@@ -1,9 +0,0 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
- $LOAD_PATH.unshift(File.dirname(__FILE__))
3
-
4
- require 'rspec'
5
- require 'ks'
6
-
7
- RSpec.configure do |config|
8
- config.order = 'random'
9
- end