Class: FlossFunding::Wedge
- Inherits:
-
Object
- Object
- FlossFunding::Wedge
- Defined in:
- lib/floss_funding/wedge.rb
Constant Summary collapse
- DANGEROUS =
if maybe_dangerous if DEBUG maybe_dangerous else warn("Unable to use DANGEROUS mode because DEBUG=false.") false end else false end
Class Method Summary collapse
-
.loaded_specs ⇒ Object
Exposed for specs: source of loaded Gem::Specification objects.
-
.namespace_candidates_for(library_name) ⇒ Object
Turn a gem name into several candidate Ruby namespace strings Examples: “google-cloud-storage” => [ “Google::Cloud::Storage”, “Google::Cloud”, “Google”, “GoogleCloudStorage” ] “alpha_beta” => [“AlphaBeta”, “Alpha”, “Alpha::Beta”].
-
.safe_const_resolve(path) ⇒ Object
Safe resolve of a constant path like “Foo::Bar” without raising.
-
.wedge! ⇒ Hash
Perform the wedge across all currently loaded specs.
Class Method Details
.loaded_specs ⇒ Object
Exposed for specs: source of loaded Gem::Specification objects
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/floss_funding/wedge.rb', line 104 def loaded_specs # Only use Gem.loaded_specs. # It is pointless to try using Bundler's version because all it does is call Gem.loaded_specs. specs, strategy = begin [::Gem.loaded_specs, "Gem.loaded_specs"] rescue StandardError => e ::FlossFunding.debug_log { "[Wedge] Gem.loaded_specs failed: #{e.class}: #{e.}" } [[], "(error)"] end ::FlossFunding.debug_log { "[Wedge] Using #{strategy}" } specs = specs.values if specs.respond_to?(:values) arr = Array(specs) ::FlossFunding.debug_log { "[Wedge] Loaded specs: count=#{arr.length}" } arr rescue StandardError => e ::FlossFunding.debug_log { "[Wedge] loaded_specs failed: #{e.class}: #{e.}" } [] end |
.namespace_candidates_for(library_name) ⇒ Object
Turn a gem name into several candidate Ruby namespace strings
Examples:
“google-cloud-storage” => [
“Google::Cloud::Storage”, “Google::Cloud”, “Google”,
“GoogleCloudStorage”
]
“alpha_beta” => [“AlphaBeta”, “Alpha”, “Alpha::Beta”]
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/floss_funding/wedge.rb', line 132 def namespace_candidates_for(library_name) ::FlossFunding.debug_log { "[Wedge] namespace_candidates_for input=#{library_name.inspect}" } return [] if library_name.nil? || library_name.empty? dash_parts = library_name.split("-") # Build CamelCase per dash part, where each part may contain underscores camel_parts = dash_parts.map { |p| camelize(p) } ::FlossFunding.debug_log { "[Wedge] camel_parts=#{camel_parts.inspect} from dash_parts=#{dash_parts.inspect}" } candidates = [] # Most likely: top-level module per dash part if camel_parts.size > 1 # Add full nested path, then its prefixes (e.g., Google::Cloud, Google) nested = camel_parts.join("::") candidates << nested (camel_parts.size - 1).downto(1) do |i| candidates << camel_parts[0, i].join("::") end end # Also attempt the fully collapsed CamelCase name candidates << camel_parts.join uniq = candidates.uniq ::FlossFunding.debug_log { "[Wedge] namespace_candidates_for output=#{uniq.inspect}" } uniq end |
.safe_const_resolve(path) ⇒ Object
Safe resolve of a constant path like “Foo::Bar” without raising
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/floss_funding/wedge.rb', line 161 def safe_const_resolve(path) ::FlossFunding.debug_log { "[Wedge] safe_const_resolve path=#{path.inspect}" } return if path.nil? || path.empty? parts = path.split("::") obj = Object parts.each do |name| # :nocov: exists = begin obj.const_defined?(name, false) rescue false end || begin Object.const_defined?(name) rescue false end # :nocov: ::FlossFunding.debug_log { "[Wedge] checking part=#{name.inspect} exists=#{exists} in obj=#{obj}" } return nil unless exists obj = begin obj.const_get(name) rescue # :nocov: ::FlossFunding.debug_log { "[Wedge] const_get failed for #{name.inspect}" } # :nocov: (return nil) end end ::FlossFunding.debug_log { "[Wedge] safe_const_resolve resolved=#{obj.inspect}" } obj rescue StandardError => e # :nocov: ::FlossFunding.debug_log { "[Wedge] safe_const_resolve error: #{e.class}: #{e.}" } nil # :nocov: end |
.wedge! ⇒ Hash
Perform the wedge across all currently loaded specs.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/floss_funding/wedge.rb', line 41 def wedge! ::FlossFunding.debug_log { "[Wedge] Starting wedge! DEBUG=#{::FlossFunding::DEBUG}" } results = {:tried => 0, :injected => 0, :details => []} specs = loaded_specs ::FlossFunding.debug_log { "[Wedge] Loaded specs count=#{specs.length}" } specs.each do |spec| unless valid_spec?(spec) ::FlossFunding.debug_log { "[Wedge] Skipping invalid spec=#{spec.inspect}" } next end if spec.name == "floss_funding" ::FlossFunding.debug_log { "[Wedge] Skipping self gem: #{spec.name}" } next end ::FlossFunding.debug_log { "[Wedge] Processing gem=#{spec.name}" } candidates = namespace_candidates_for(spec.name) ::FlossFunding.debug_log { "[Wedge] Candidates for #{spec.name}: #{candidates.inspect}" } injected_into = [] # Dangerous effort: try to require the gem before resolving constants attempt_require_for_spec(spec, candidates) if DANGEROUS candidates.each do |ns| ::FlossFunding.debug_log { "[Wedge] Resolving constant path=#{ns} for gem=#{spec.name}" } mod = safe_const_resolve(ns) unless mod.is_a?(Module) ::FlossFunding.debug_log { "[Wedge] Not a Module or missing: #{ns} => #{mod.inspect}" } next end begin inc_path = spec.loaded_from || guess_including_path(spec) ::FlossFunding.debug_log { "[Wedge] Including Poke into #{ns} with path=#{inc_path.inspect}" } mod.send(:include, ::FlossFunding::Poke.new(inc_path, :wedge => true)) injected_into << ns ::FlossFunding.debug_log { "[Wedge] Included successfully into #{ns}" } rescue StandardError => e # :nocov: ::FlossFunding.debug_log { "[Wedge] Include failed for #{ns}: #{e.class}: #{e.}" } # Swallow and continue; this is best-effort to probe many libs # :nocov: end end results[:tried] += 1 results[:injected] += injected_into.size.positive? ? 1 : 0 details = {:gem => spec.name, :injected_into => injected_into} results[:details] << details ::FlossFunding.debug_log { "[Wedge] Result for #{spec.name}: #{details.inspect}" } end if DEBUG puts "[Wedge] Finished wedge!\n#{results.inspect}" else puts "[Wedge] Finished wedge!\n#{render_summary_table(results)}" end results end |