ivar 0.2.0

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.
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "did_you_mean"
4
+
5
+ module Ivar
6
+ # Provides validation for instance variables
7
+ module Validation
8
+ # Checks instance variables against class analysis
9
+ # @param add [Array<Symbol>] Additional instance variables to allow
10
+ # @param policy [Symbol, Policy] The policy to use for handling unknown variables
11
+ def check_ivars(add: [], policy: nil)
12
+ # Get the policy to use
13
+ policy ||= get_check_policy
14
+
15
+ # Get the class analysis from the cache
16
+ analysis = Ivar.get_analysis(self.class)
17
+
18
+ # Get all instance variables defined in the current object
19
+ # These are the ones the user has explicitly defined before calling check_ivars
20
+ defined_ivars = instance_variables.map(&:to_sym)
21
+
22
+ # Add any additional allowed variables
23
+ allowed_ivars = defined_ivars + add
24
+
25
+ # Get all instance variable references from the analysis
26
+ # This includes location information for each reference
27
+ references = analysis.ivar_references
28
+
29
+ # Find references to unknown variables (those not in allowed_ivars)
30
+ unknown_refs = references.reject { |ref| allowed_ivars.include?(ref[:name]) }
31
+
32
+ # Handle unknown variables according to the policy
33
+ policy_instance = Ivar.get_policy(policy)
34
+ policy_instance.handle_unknown_ivars(unknown_refs, self.class, allowed_ivars)
35
+ end
36
+
37
+ # For backward compatibility - delegates to check_ivars with warn_once policy
38
+ # @param add [Array<Symbol>] Additional instance variables to allow
39
+ def check_ivars_once(add: [])
40
+ check_ivars(add: add, policy: :warn_once)
41
+ end
42
+
43
+ private
44
+
45
+ # Get the check policy for this instance
46
+ # @return [Symbol, Policy] The check policy
47
+ def get_check_policy
48
+ # If the class has an ivar_check_policy method, use that
49
+ return self.class.ivar_check_policy if self.class.respond_to?(:ivar_check_policy)
50
+
51
+ # Otherwise, use the global default
52
+ Ivar.check_policy
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ivar
4
+ VERSION = "0.2.0"
5
+ end
data/lib/ivar.rb ADDED
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ivar/version"
4
+ require_relative "ivar/prism_analysis"
5
+ require_relative "ivar/policies"
6
+ require_relative "ivar/validation"
7
+ require_relative "ivar/macros"
8
+ require_relative "ivar/auto_check"
9
+ require "prism"
10
+ require "did_you_mean"
11
+
12
+ module Ivar
13
+ @analysis_cache = {}
14
+ @checked_classes = {}
15
+ @default_check_policy = :warn
16
+
17
+ # Returns a cached analysis for the given class or module
18
+ # Creates a new analysis if one doesn't exist in the cache
19
+ def self.get_analysis(klass)
20
+ @analysis_cache[klass] ||= PrismAnalysis.new(klass)
21
+ end
22
+
23
+ # Checks if a class has been validated already
24
+ # @param klass [Class] The class to check
25
+ # @return [Boolean] Whether the class has been validated
26
+ def self.class_checked?(klass)
27
+ @checked_classes.key?(klass)
28
+ end
29
+
30
+ # Marks a class as having been checked
31
+ # @param klass [Class] The class to mark as checked
32
+ def self.mark_class_checked(klass)
33
+ @checked_classes[klass] = true
34
+ end
35
+
36
+ # For testing purposes - allows clearing the cache
37
+ def self.clear_analysis_cache
38
+ @analysis_cache.clear
39
+ @checked_classes.clear
40
+ end
41
+
42
+ # Get the default check policy
43
+ # @return [Symbol] The default check policy
44
+ def self.check_policy
45
+ @default_check_policy
46
+ end
47
+
48
+ # Set the default check policy
49
+ # @param policy [Symbol, Policy] The default check policy
50
+ def self.check_policy=(policy)
51
+ @default_check_policy = policy
52
+ end
53
+ end
data/sig/ivar.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Ivar
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
data/test_file.rb ADDED
@@ -0,0 +1 @@
1
+ class MockClass; end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ivar
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Avdi Grimm
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: prism
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.2'
26
+ description: |
27
+ Ruby instance variables are so convenient - you don't even need to declare them!
28
+ But... they are also dangerous, because a mispelled variable name results in `nil`
29
+ instead of an error.
30
+
31
+ Why not have the best of both worlds? Ivar lets you use plain-old instance variables,
32
+ and automatically checks for typos.
33
+
34
+ Ivar waits until an instance is created to do the checking, then uses Prism to look
35
+ for variables that don't match what was set in initialization. So it's a little bit
36
+ dynamic, a little bit static. It doesn't encumber your instance variable reads and
37
+ writes with any extra checking. And with the `:warn_once` policy, it won't overwhelm
38
+ you with output.
39
+ email:
40
+ - avdi@avdi.codes
41
+ executables: []
42
+ extensions: []
43
+ extra_rdoc_files: []
44
+ files:
45
+ - ".augment-guidelines"
46
+ - ".devcontainer/Dockerfile"
47
+ - ".devcontainer/devcontainer.json"
48
+ - ".standard.yml"
49
+ - ".vscode/extensions.json"
50
+ - ".vscode/settings.json"
51
+ - CHANGELOG.md
52
+ - CODE_OF_CONDUCT.md
53
+ - LICENSE.txt
54
+ - README.md
55
+ - Rakefile
56
+ - examples/sandwich_inheritance.rb
57
+ - examples/sandwich_with_checked.rb
58
+ - examples/sandwich_with_checked_once.rb
59
+ - examples/sandwich_with_ivar_block.rb
60
+ - examples/sandwich_with_ivar_macro.rb
61
+ - examples/sandwich_with_kwarg.rb
62
+ - ivar.gemspec
63
+ - lib/ivar.rb
64
+ - lib/ivar/auto_check.rb
65
+ - lib/ivar/checked.rb
66
+ - lib/ivar/macros.rb
67
+ - lib/ivar/policies.rb
68
+ - lib/ivar/prism_analysis.rb
69
+ - lib/ivar/validation.rb
70
+ - lib/ivar/version.rb
71
+ - sig/ivar.rbs
72
+ - test_file.rb
73
+ homepage: https://github.com/avdi/ivar
74
+ licenses:
75
+ - MIT
76
+ metadata:
77
+ allowed_push_host: https://rubygems.org
78
+ homepage_uri: https://github.com/avdi/ivar
79
+ source_code_uri: https://github.com/avdi/ivar
80
+ changelog_uri: https://github.com/avdi/ivar/blob/main/CHANGELOG.md
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 3.4.0
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubygems_version: 3.6.7
96
+ specification_version: 4
97
+ summary: Automatically check instance variables for typos.
98
+ test_files: []