Skip to content

Commit b691184

Browse files
authored
Merge pull request #87 from aetherknight/add-rubocop
Add rubocop and address most lints
2 parents 925d11c + 10d1d09 commit b691184

22 files changed

Lines changed: 725 additions & 614 deletions

.github/dependabot.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ updates:
44
directory: "/"
55
schedule:
66
interval: "quarterly"
7-
- package-ecosystem: "bundler"
8-
directory: "/"
9-
schedule:
10-
interval: "quarterly"
7+
# TODO: the bundler dependency updater doesn't seem to handle the Gemfile
8+
# using the gemspec? Figure this out and re-enable, if possible
9+
# - package-ecosystem: "bundler"
10+
# directory: "/"
11+
# schedule:
12+
# interval: "quarterly"

.rubocop.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# The behavior of RuboCop can be controlled via the .rubocop.yml
2+
# configuration file. It makes it possible to enable/disable
3+
# certain cops (checks) and to alter their behavior if they accept
4+
# any parameters. The file can be placed either in your home
5+
# directory or in some project directory.
6+
#
7+
# RuboCop will start looking for the configuration file in the directory
8+
# where the inspected file is and continue its way up to the root directory.
9+
#
10+
# See https://docs.rubocop.org/rubocop/configuration
11+
plugins:
12+
- 'rubocop-rake'
13+
- 'rubocop-rspec'
14+
15+
Layout/LineLength:
16+
Max: 120
17+
18+
Metrics/BlockLength:
19+
Exclude:
20+
- "spec/**/*.rb"
21+
- "*.gemspec"
22+
23+
Metrics/MethodLength:
24+
Enabled: false
25+
26+
Naming/FileName:
27+
Exclude:
28+
# This file is deliberately named with dashes, to match the package name
29+
- 'lib/recursive-open-struct.rb'
30+
31+
Style/CommentedKeyword:
32+
Exclude:
33+
- "spec/**/*.rb"
34+
35+
Style/Documentation:
36+
Enabled: false
37+
38+
# Can't really disable this in the gemspec file (it is reported on line 1, but
39+
# line 1 has the frozen string literal comment)
40+
Gemspec/RequiredRubyVersion:
41+
Enabled: false
42+
# TODO: should I set a required ruby version? At the moment, the project policy
43+
# is to officially support supported Ruby versions (and JRuby), but to not
44+
# officially support no-longer-maintained Ruby versions.
45+
46+
RSpec/ExampleLength:
47+
Enabled: false
48+
RSpec/NestedGroups:
49+
Enabled: false
50+
RSpec/MultipleExpectations:
51+
Enabled: false
52+
53+
# Not sure why this one still fails -- the specs are all in a
54+
# recursive_open_struct directory.
55+
RSpec/SpecFilePathFormat:
56+
Enabled: false

.travis.yml

Lines changed: 0 additions & 34 deletions
This file was deleted.

CONTRIBUTING.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,31 @@ When contributing code that changes behavior or fixes bugs, please include unit
4949
tests to cover the new behavior or to provide regression testing for bugs.
5050
Also, treat the unit tests as documentation --- make sure they are clean,
5151
clear, and concise, and well organized.
52+
53+
## Testing and Development
54+
55+
- This project uses RSpec to both document and test behavior. Please structure
56+
your tests help someone understand what is being tested.
57+
- It also uses rubocop to autoformat and lint the project. Run it locally
58+
before committing.
59+
60+
You can run both the test suite and the linter with the following commands:
61+
62+
```sh
63+
# install/update dependencies
64+
bundle
65+
66+
# run the test suite and linter
67+
bundle exec rake
68+
69+
# have the linter apply all safe fixes (eg, autoformatting)
70+
bundle exec rake rubocop:autocorrect
71+
```
72+
73+
## Release Process
74+
75+
1. Update CHANGELOG.md and lib/recursive_open_struct/version.rb
76+
2. Run `bundle exec rake update_authors`
77+
3. Make a version release commit
78+
4. Run the release task (it will tag, build, push code, push package):
79+
`bundle exec rake release`

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
# frozen_string_literal: true
2+
13
source 'https://rubygems.org'
24
gemspec

Rakefile

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# encoding: utf-8
1+
# frozen_string_literal: true
22

33
require 'rubygems'
44
require 'bundler/gem_tasks'
@@ -9,52 +9,56 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
99
end
1010
namespace :spec do
1111
if RUBY_VERSION =~ /^1\.8/
12-
desc "Rspec code coverage (1.8.7)"
12+
desc 'Rspec code coverage (1.8.7)'
1313
RSpec::Core::RakeTask.new(:coverage) do |spec|
1414
spec.pattern = 'spec/**/*_spec.rb'
1515
spec.rcov = true
1616
end
1717
else
18-
desc "Rspec code coverage (1.9+)"
18+
desc 'Rspec code coverage (1.9+)'
1919
task :coverage do
2020
ENV['COVERAGE'] = 'true'
21-
Rake::Task["spec"].execute
21+
Rake::Task['spec'].execute
2222
end
2323
end
2424
end
2525

26+
require 'rubocop/rake_task'
27+
RuboCop::RakeTask.new
28+
2629
require 'rdoc/task'
2730
Rake::RDocTask.new do |rdoc|
28-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
31+
version = File.exist?('VERSION') ? File.read('VERSION') : ''
2932

3033
rdoc.rdoc_dir = 'rdoc'
3134
rdoc.title = "recursive-open-struct #{version}"
3235
rdoc.rdoc_files.include('README*')
3336
rdoc.rdoc_files.include('lib/**/*.rb')
3437
end
3538

36-
task :default => :spec
39+
task default: %i[spec rubocop]
3740

41+
desc 'Ensure all files have appropriate permissions before building a package'
3842
task :fix_permissions do
39-
File.umask 0022
43+
File.umask 0o022
4044
filelist = `git ls-files`.split("\n")
41-
FileUtils.chmod 0644, filelist, :verbose => true
42-
FileUtils.chmod 0755, ['lib','spec'], :verbose => true
45+
FileUtils.chmod 0o644, filelist, verbose: true
46+
FileUtils.chmod 0o755, %w[lib spec], verbose: true
4347
end
4448

45-
desc "Update the AUTHORS.txt file"
49+
desc 'Update the AUTHORS.txt file'
4650
task :update_authors do
4751
authors = `git log --format="%aN <%aE>"|sort -f|uniq`
4852
File.open('AUTHORS.txt', 'w') do |f|
4953
f.write("Recursive-open-struct was written by these fine people:\n\n")
50-
f.write(authors.split("\n").map { |a| "* #{a}" }.join( "\n" ))
54+
f.write(authors.split("\n").map { |a| "* #{a}" }.join("\n"))
5155
f.write("\n")
5256
end
5357
end
5458

55-
task :build => [:update_authors, :fix_permissions]
59+
task build: %i[update_authors fix_permissions]
5660

57-
desc "Run an interactive pry shell with ros required"
61+
desc 'Run an interactive pry shell with ros required'
5862
task :pry do
59-
sh "pry -I lib -r recursive-open-struct"
63+
sh 'pry -I lib -r recursive-open-struct'
6064
end

lib/recursive-open-struct.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1+
# frozen_string_literal: true
2+
13
require 'recursive_open_struct'

lib/recursive_open_struct.rb

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# frozen_string_literal: true
2+
13
require 'ostruct'
24
require 'recursive_open_struct/version'
35

@@ -12,6 +14,7 @@
1214
# TODO: `#*_as_a_hash` deprecated. Nested hashes can be referenced using
1315
# `#to_h`.
1416

17+
# rubocop:disable Metrics/ClassLength
1518
class RecursiveOpenStruct < OpenStruct
1619
include Dig if OpenStruct.public_instance_methods.include? :dig
1720

@@ -28,7 +31,9 @@ def self.default_options
2831
}
2932
end
3033

31-
def initialize(hash=nil, passed_options={})
34+
# rubocop:disable Lint/MissingSuper
35+
# Intentionally doesn't call super and initializes +@table+ itself.
36+
def initialize(hash = nil, passed_options = {})
3237
hash = hash.to_h if [hash.is_a?(RecursiveOpenStruct), hash.is_a?(OpenStruct)].any?
3338
hash ||= {}
3439

@@ -40,6 +45,7 @@ def initialize(hash=nil, passed_options={})
4045

4146
@sub_elements = {}
4247
end
48+
# rubocop:enable Lint/MissingSuper
4349

4450
def marshal_load(attributes)
4551
hash, @options = attributes
@@ -69,17 +75,17 @@ def to_h
6975

7076
# TODO: deprecated, unsupported by OpenStruct. OpenStruct does not consider
7177
# itself to be a "kind of" Hash.
72-
alias_method :to_hash, :to_h
78+
alias to_hash to_h
7379

7480
# Continue supporting older rubies -- JRuby 9.1.x.x is still considered
7581
# stable, but is based on Ruby
7682
# 2.3.x and so uses :modifiable instead of :modifiable?. Furthermore, if
7783
# :modifiable is private, then make :modifiable? private too.
78-
if !OpenStruct.private_instance_methods.include?(:modifiable?)
84+
unless OpenStruct.private_instance_methods.include?(:modifiable?)
7985
if OpenStruct.private_instance_methods.include?(:modifiable)
80-
alias_method :modifiable?, :modifiable
86+
alias modifiable? modifiable
8187
elsif OpenStruct.public_instance_methods.include?(:modifiable)
82-
alias_method :modifiable?, :modifiable
88+
alias modifiable? modifiable
8389
private :modifiable?
8490
end
8591
end
@@ -89,7 +95,7 @@ def [](name)
8995
v = @table[key_name]
9096
if v.is_a?(Hash)
9197
@sub_elements[key_name] ||= _create_sub_element_(v, mutate_input_hash: true)
92-
elsif v.is_a?(Array) and @options[:recurse_over_arrays]
98+
elsif v.is_a?(Array) && @options[:recurse_over_arrays]
9399
@sub_elements[key_name] ||= recurse_over_array(v)
94100
@sub_elements[key_name] = recurse_over_array(@sub_elements[key_name])
95101
else
@@ -100,7 +106,7 @@ def [](name)
100106
if private_instance_methods.include?(:modifiable?) || public_instance_methods.include?(:modifiable?)
101107
def []=(name, value)
102108
key_name = _get_key_from_table_(name)
103-
tbl = modifiable? # Ensure we are modifiable
109+
tbl = modifiable? # Ensure we are modifiable
104110
@sub_elements.delete(key_name)
105111
tbl[key_name] = value
106112
end
@@ -120,19 +126,20 @@ def respond_to_missing?(mid, include_private = false)
120126

121127
# Adapted implementation of method_missing to accommodate the differences
122128
# between ROS and OS.
129+
# rubocop:disable Metrics/AbcSize
130+
# rubocop:disable Metrics/PerceivedComplexity
123131
def method_missing(mid, *args)
124132
len = args.length
125133
if mid =~ /^(.*)=$/
126-
if len != 1
127-
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
128-
end
134+
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1) if len != 1
135+
129136
# self[$1.to_sym] = args[0]
130137
# modifiable?[new_ostruct_member!($1.to_sym)] = args[0]
131-
new_ostruct_member!($1.to_sym)
138+
new_ostruct_member!(::Regexp.last_match(1).to_sym)
132139
public_send(mid, args[0])
133-
elsif len == 0
140+
elsif len.zero?
134141
key = mid
135-
key = $1 if key =~ /^(.*)_as_a_hash$/
142+
key = ::Regexp.last_match(1) if key =~ /^(.*)_as_a_hash$/
136143
if @table.key?(_get_key_from_table_(key))
137144
new_ostruct_member!(key)
138145
public_send(mid)
@@ -147,6 +154,8 @@ def method_missing(mid, *args)
147154
raise err
148155
end
149156
end
157+
# rubocop:enable Metrics/PerceivedComplexity
158+
# rubocop:enable Metrics/AbcSize
150159

151160
def freeze
152161
@table.each_key do |key|
@@ -160,7 +169,7 @@ def freeze
160169
# 2.4.0.
161170
def new_ostruct_member(name)
162171
key_name = _get_key_from_table_(name)
163-
unless self.singleton_class.method_defined?(name.to_sym)
172+
unless singleton_class.method_defined?(name.to_sym)
164173
class << self; self; end.class_eval do
165174
define_method(name) do
166175
self[key_name]
@@ -185,7 +194,12 @@ class << self; self; end.class_eval do
185194

186195
def delete_field(name)
187196
sym = _get_key_from_table_(name)
188-
singleton_class.__send__(:remove_method, sym, "#{sym}=") rescue NoMethodError # ignore if methods not yet generated.
197+
begin
198+
singleton_class.__send__(:remove_method, sym, "#{sym}=")
199+
rescue StandardError
200+
# ignore if methods not yet generated.
201+
NoMethodError
202+
end
189203
@sub_elements.delete(sym)
190204
@table.delete(sym)
191205
end
@@ -203,8 +217,9 @@ def initialize_dup(orig)
203217
end
204218

205219
def _get_key_from_table_(name)
206-
return name.to_s if @table.has_key?(name.to_s)
207-
return name.to_sym if @table.has_key?(name.to_sym)
220+
return name.to_s if @table.key?(name.to_s)
221+
return name.to_sym if @table.key?(name.to_sym)
222+
208223
name
209224
end
210225

@@ -222,5 +237,5 @@ def recurse_over_array(array)
222237
end
223238
array
224239
end
225-
226240
end
241+
# rubocop:enable Metrics/ClassLength

0 commit comments

Comments
 (0)