suggest_rb 0.3.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: e4b15e6cb0b18984749d2abbdd32835774de3e480374dfc3d4a9dd7393f1b208
4
- data.tar.gz: 71444761f35ef08b561a0e3f5cfc8c84061ab9ddc974f494f99bd0b2b42b163b
2
+ SHA1:
3
+ metadata.gz: 34aee46d7b04cc746443cae1623bc6ec09fdfc6c
4
+ data.tar.gz: 9168c4b4db034e5c46645b7e6a2b8c2aa359addd
5
5
  SHA512:
6
- metadata.gz: 42fd7d3197b65a1c708533545f16c8f395574a26275fa48a32bcf26589e98b5c98e8aedbbc79201a98ec582da2b1253d6122b1907722d6588480aa039d88ee30
7
- data.tar.gz: daa3d40c2ca895d59552d6ae4dc9c6dd37619e8647493e74d1bdc8ac0202dbadddecb80f723f4c7494e9b6a4eb26ef1bbbb0ccd7ddaecfaad056a00e08ffbf08
6
+ metadata.gz: 04e21185e022abc6113aa0cd130ad78ab1ad770712130b5d728ea4aef6515b734e88e4b68c79fcadec8e87e8245d033cd49835fa00e0b5e64e60698b854f40bb
7
+ data.tar.gz: 68483b98b9fa8402c0e569f2088deb65fcc5c7407b460f6a143fdbdf80fd09389b9eb216b6823067586c62a68f35581364a439102111f5ef938998f2d0069e2d
data/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  tells you which method does the thing you want to do
4
4
 
5
+ ## Disclaimer
6
+
7
+ I don't recommend you ship this in your Gemfile. Keep it in your system's gems (e.g. `gem install`) and load it as needed (e.g. `irb -rsuggest`, `RUBY_OPT=-rsuggest irb`, etc)
8
+
5
9
  ## Installation
6
10
 
7
11
  ```
@@ -19,11 +23,11 @@ require 'suggest'
19
23
 
20
24
  # You can also specify the args you want that method to take
21
25
  [1,2,3].what_returns? [1], args: [1]
22
- => [:sample, :first, :take, :grep, :min]
26
+ => [:first, :take, :grep, :min]
23
27
 
24
28
  # By default, it only returns methods that don't mutate the object
25
29
  [1,2,3].what_returns? [1], args: [1], allow_mutation: true
26
- => [:sample, :first, :take, :shift, :grep, :min]
30
+ => [:first, :take, :shift, :grep, :min]
27
31
 
28
32
  # It works on several core modules including String
29
33
  "HELLO".what_returns? "hello"
@@ -55,6 +59,14 @@ require 'suggest'
55
59
  # And you can give it a block as well
56
60
  [1,2,3,4].what_mutates? [2,4] { |n| n % 2 == 0 }
57
61
  => [:select!, :keep_if]
62
+
63
+ # It respects the ruby version
64
+ # ruby 2.4.3
65
+ {a: 1, b: 2}.what_returns?({})
66
+ => []
67
+ # ruby 2.5.0
68
+ {a: 1, b: 2}.what_returns?({})
69
+ => [:slice]
58
70
  ```
59
71
 
60
72
  ## Note to Self
data/lib/suggest.rb CHANGED
@@ -47,27 +47,22 @@ module Suggest
47
47
  [Numeric, :dup],
48
48
  ])
49
49
 
50
- module Mixin
51
- def what_returns?(expected, args: [], allow_mutation: false)
52
- block = Proc.new if block_given?
53
-
54
- applicable_methods = self.methods.map(&method(:method)).select do |m|
55
- SUGGEST_MODS.include?(m.owner) &&
56
- !INCONSISTENT.include?([m.owner, m.name]) &&
57
- !TOO_COMPLICATED.include?([m.owner, m.name])
58
- end
50
+ SELECTOR = ->(m) do
51
+ SUGGEST_MODS.include?(m.owner) &&
52
+ !INCONSISTENT.include?([m.owner, m.name]) &&
53
+ !TOO_COMPLICATED.include?([m.owner, m.name])
54
+ end
59
55
 
60
- applicable_methods.select do |m|
56
+ module Mixin
57
+ def what_returns?(expected, args: [], allow_mutation: false, allow_not_public: false, &block)
58
+ methods.map(&method(:method)).select(&SELECTOR).select do |m|
61
59
  arity = m.arity
62
- next unless arity == -1 || arity == args.count
60
+ next unless arity < 0 || arity == args.count
63
61
 
64
62
  post = clone
65
- if block
66
- next if UNSAFE_WITH_BLOCK.include?([m.owner, m.name])
67
- result = post.public_send(m.name, *args, &block) rescue next
68
- else
69
- result = post.public_send(m.name, *args) rescue next
70
- end
63
+
64
+ next if block && UNSAFE_WITH_BLOCK.include?([m.owner, m.name])
65
+ result = post.__send__(allow_not_public ? :send : :public_send, m.name, *args, &block) rescue next
71
66
 
72
67
  next unless allow_mutation || self == post
73
68
 
@@ -75,31 +70,17 @@ module Suggest
75
70
  end.map(&:name)
76
71
  end
77
72
 
78
- def what_mutates?(expected, opts = {})
79
- args = opts[:args] || []
80
- block = Proc.new if block_given?
81
-
82
- applicable_methods = self.methods.map(&method(:method)).select do |m|
83
- SUGGEST_MODS.include?(m.owner) &&
84
- !INCONSISTENT.include?([m.owner, m.name]) &&
85
- !TOO_COMPLICATED.include?([m.owner, m.name])
86
- end
87
-
88
- applicable_methods.select do |m|
73
+ def what_mutates?(expected, args: [], allow_not_public: false, **opts, &block)
74
+ methods.map(&method(:method)).select(&SELECTOR).select do |m|
89
75
  arity = m.arity
90
- next unless arity == -1 || arity == args.count
76
+ next unless arity < 0 || arity == args.count
91
77
 
92
78
  post = clone
93
- if block
94
- next if UNSAFE_WITH_BLOCK.include?([m.owner, m.name])
95
- result = post.public_send(m.name, *args, &block) rescue next
96
- else
97
- result = post.public_send(m.name, *args) rescue next
98
- end
99
79
 
100
- if opts.key?(:returns)
101
- next unless Suggest.eq?(result, opts[:returns])
102
- end
80
+ next if block && UNSAFE_WITH_BLOCK.include?([m.owner, m.name])
81
+ result = post.__send__(allow_not_public ? :send : :public_send, m.name, *args, &block) rescue next
82
+
83
+ next if opts.key?(:returns) && !Suggest.eq?(result, opts[:returns])
103
84
 
104
85
  Suggest.eq?(post, expected)
105
86
  end.map(&:name)
@@ -110,18 +91,28 @@ module Suggest
110
91
  result.is_a?(expected.class) && result == expected
111
92
  end
112
93
 
94
+ def self.suggestable!(mod, **corrections) # unsafe_with_block: [], inconsistent: [], too_complicated: []
95
+ raise ArgumentError.new("Must support smart comparison (implement «#{mod}#==»)") if mod.instance_method(:==).owner == BasicObject
96
+
97
+ SUGGEST_MODS << mod
98
+ %w[unsafe_with_block inconsistent too_complicated].each do |correction|
99
+ c = Suggest.const_get(correction.upcase)
100
+ [mod].product(corrections.fetch(correction, [])).each(&c.method(:<<))
101
+ end
102
+ mod.include(Suggest::Mixin) unless mod.ancestors.include?(Suggest::Mixin)
103
+ end
104
+
113
105
  def self.suggestable_methods
114
- candidates = []
115
- SUGGEST_MODS.each do |mod|
106
+ SUGGEST_MODS.each_with_object([]) do |mod, candidates|
116
107
  owned_methods = mod.instance_methods.select { |m| mod.instance_method(m).owner == mod }
117
108
  next if owned_methods.none?
118
109
  candidates += [mod].product(owned_methods)
119
- end
120
-
121
- candidates.reject do |m|
110
+ end.reject do |m|
122
111
  INCONSISTENT.include?(m) || TOO_COMPLICATED.include?(m)
123
112
  end
124
113
  end
125
114
  end
126
115
 
127
- Object.include(Suggest::Mixin)
116
+ Suggest::SUGGEST_MODS.each do |mod|
117
+ mod.include(Suggest::Mixin) unless mod.ancestors.include?(Suggest::Mixin)
118
+ end
@@ -1,3 +1,3 @@
1
1
  module Suggest
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: suggest_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Bodah
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-18 00:00:00.000000000 Z
11
+ date: 2019-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -116,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
116
  version: '0'
117
117
  requirements: []
118
118
  rubyforge_project:
119
- rubygems_version: 2.7.6
119
+ rubygems_version: 2.5.2.3
120
120
  signing_key:
121
121
  specification_version: 4
122
122
  summary: tells you which method does the thing you want to do