kyrylo / pry-theme

An easy way to customize Pry colors via theme files
zlib License
171 stars 14 forks source link

pry-theme try command cannot find themes, despite them existing in theme directory #42

Closed kzrbill closed 10 years ago

kzrbill commented 10 years ago

[1] pry(main)> pry-theme try zenburn Cannot find "zenburn" amongst themes in /Users/xxx/.pry/themes

Theme exists at path /Users/xxx/.pry/themes/zenburn.prytheme.rb

Ruby 2.0.0 pry (0.10.0) pry-theme (1.1.2)

kyrylo commented 10 years ago

Hello, @kzrbill! Thank you for filing the issue!

Does pry-theme current return anything?

kzrbill commented 10 years ago

[2] pry(main)> pry-theme current NoMethodError: undefined method name' for nil:NilClass from /Users/xxx/.rvm/gems/ruby-2.0.0-p353/gems/pry-theme-1.1.2/lib/pry-theme/commands.rb:147:inblock (2 levels) in def_current'

Line 147 output.puts ThemeList.current_theme.name

ThemeList.current_theme is nil.

jmromer commented 10 years ago

I've started running into a similar problem for some reason. Pry won't load any color scheme at all except for the default one.

~ % ls ~/.pry/themes
railscasts.prytheme.rb  twilight.prytheme.rb
~ % cat .pryrc
Pry.config.theme = "railscasts"
Pry.config.editor = "subl -wn"

Pry.prompt = [
  proc { |obj, nest_level, _| prompt = ">> " },
  proc { |obj, nest_level, _| prompt = "   " }
]

Pry.config.exception_handler = proc do |output, exception, _|
  output.puts "#{exception.class}: #{exception.message}"
  exception.backtrace.each do |bt|
    puts "\tfrom: #{bt}"
    break if bt =~ /^\(pry\)/
  end
end
~ % pry
>> PryTheme
=> PryTheme
>> pry-theme try railscasts
Cannot find "railscasts" amongst themes in /Users/puller/.pry/themes
>> pry-theme list

>>
>> pry-theme current
NoMethodError: undefined method `name' for nil:NilClass
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-theme-1.1.2/lib/pry-theme/commands.rb:147:in `block (2 levels) in def_current'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/slop-3.5.0/lib/slop.rb:260:in `call'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/slop-3.5.0/lib/slop.rb:260:in `parse!'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/slop-3.5.0/lib/slop.rb:235:in `parse!'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/command.rb:576:in `call'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/command.rb:456:in `call_with_hooks'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/command.rb:427:in `call_safely'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/command.rb:369:in `process_line'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/command_set.rb:393:in `process_line'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_instance.rb:402:in `process_command'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_instance.rb:433:in `process_command_safely'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_instance.rb:270:in `handle_line'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_instance.rb:241:in `block (2 levels) in eval'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_instance.rb:240:in `catch'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_instance.rb:240:in `block in eval'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_instance.rb:239:in `catch'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_instance.rb:239:in `eval'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/repl.rb:77:in `block in repl'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/repl.rb:67:in `loop'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/repl.rb:67:in `repl'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/repl.rb:38:in `block in start'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/input_lock.rb:61:in `call'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/input_lock.rb:61:in `__with_ownership'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/input_lock.rb:79:in `with_ownership'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/repl.rb:38:in `start'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/repl.rb:15:in `start'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/pry_class.rb:169:in `start'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/cli.rb:219:in `block in <top (required)>'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/cli.rb:83:in `call'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/cli.rb:83:in `block in parse_options'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/cli.rb:83:in `each'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/lib/pry/cli.rb:83:in `parse_options'
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-0.10.0/bin/pry:16:in `<top (required)>'
    from: /usr/local/var/rbenv/versions/2.1.2/bin/pry:23:in `load'
    from: /usr/local/var/rbenv/versions/2.1.2/bin/pry:23:in `<main>'
>>
>> PryTheme::ThemeList.current_theme
=> nil
~ % rbenv version
2.1.2 (set by /usr/local/var/rbenv/version)
~ % gem list | grep pry
pry (0.10.0)
pry-theme (1.1.2)
jmromer commented 10 years ago

I can install themes from the remote collection, but pry can't see them once I exit:

If I install a theme from the official collection and try it out, it works

>> pry-theme install autumn
Installing "autumn" from Pry Theme Collection...
Successfully installed "autumn"!
>> pry-theme try autumn
Using "autumn" theme

(The correct colors show up.)

But after exiting and restarting pry, pry-theme can't see the file anymore:

>> pry-theme list

>> pry-theme try autumn
Cannot find "autumn" amongst themes in /Users/puller/.pry/themes
>> exit

even though they're where they're supposed to be

themes % ls /Users/puller/.pry/themes
autumn.prytheme.rb  railscasts.prytheme.rb  tomorrow-night.prytheme.rb  twilight.prytheme.rb

If I run pry-theme list immediately after installing a theme from the remote collection, pry-theme throws an error:

>> pry-theme list
NoMethodError: undefined method `activate' for nil:NilClass
    from: /usr/local/var/rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/pry-theme-1.1.2/lib/pry-theme/preview.rb:14:in `short'
kzrbill commented 10 years ago

Yep @jmromer. My issue is completely consistent with yours. What's interesting though is that when I run PryTheme::WhenStartedHook.new() to load_themes, the themes are loading. Would suggest that the hook is broken. Hah - just seen your post @kyrylo (honest). Yep - that makes sense then.

yorickpeterse commented 10 years ago

Same problem here, installing pry-rescue as mentioned by @kyrylo seems to magically resolve the problem. This is using Pry version 0.10.0 on Ruby 2.1.2.

JoshCheek commented 10 years ago

Until this gets fixed in Pry, you can get around it by adding the following to your ~/.pryrc

# ensure hooks have been initialized prior to use (https://github.com/pry/pry/issues/1271)
Pry.config.hooks

# ensure pry-theme hook is added since it might have gotten "lost"
Pry.config.hooks.add_hook(
  :when_started,
  :pry_theme,
  PryTheme::WhenStartedHook.new
)
kyrylo commented 10 years ago

All hail @JoshCheek, he fixed this!

So, just wait for the new Pry release and everything will be magic again (no idea when that will happen, though).

JoshCheek commented 10 years ago

@kyrylo, you can fix it for your lib in the interim with a short/simple hack:

ruby -p -i -e 'puts "Pry.config.hooks" if /Pry\.config/' `gem which pry-theme`
kyrylo commented 10 years ago

Could you please explain what this command does? :)

JoshCheek commented 10 years ago

@kyrylo, you can fix it for your lib in the interim with a short/simple hack:

ruby -p -i -e 'puts "Pry.config.hooks" if /Pry\.config/' `gem which pry-theme`

Could you please explain what this command does? :)

Sure. I realized after writing this, that I didn't switch over to bash to try out all these commands, so there might be some slight errors, as I've only run translations of this code for my shell.

What we need to do

We can hack around the bug in that file if we add Pry.config.hooks before the line that tries to add the new hook. This is because the first invocation will set the value correctly, but return the wrong value. All invocations after that first one will return the correct value as they go down a different method_missing path.

Find the file to edit

gem which pry-theme returns the path to the file that is loaded when we write require "pry-theme"

For example, try:

cat `gem which pry-theme`
echo `gem which pry-theme`

Print that file out, line by line

The -p flag tells Ruby to iterate over the file, line-by-line, setting the current line into $_, and then invoking the ruby program, and then printing $_, and moving onto the next line. Here is a hypothetical simplified implementation:

File.foreach(ARGV[0]) do |line|
  $_ = line
  ruby_program.call
  print $_
end

Now we need to give it a ruby program, we'll choose something simple, a program that does nothing (ie the program is an empty string), and we'll provide it with the -e flag.

ruby -p -e "" `gem which pry-theme`

This should print out the installed "lib/pry-theme.rb" file. As another example, we could print it out with each line reversed:

ruby -p -e '$_ = $_.reverse' `gem which pry-theme`

Insert the fix into the output

So, now we just want to print the fix when we see that $_ is the line trying access the hooks. We could do it it with something like this:

puts "Pry.config.hooks" if $_ =~ /\APry\.config\.hooks\Z/

But it's a little bit syntactically dense. We can make it terser (and I'd certainly entertain the counter-argument that this isn't necessarily better) by just passing the regex directly to the conditional. Whenever Ruby sees a regex being used as a conditional, it would be tautological in the sense that a regex is an object, and thus should always be true. However, it treats this condition as special (our Perl heritage), and matches it, instead, against $_

$_ = "abc"  # => "abc"
!!/a/       # => true
!!/x/       # => false

This means we can omit the comparison and give the regex directly:

puts "Pry.config.hooks" if /\APry\.config\.hooks\Z/

And just to reduce the probability of breaking if there's some other version out there with slightly different code, I also relaxed the regex:

puts "Pry.config.hooks" if /Pry\.config/

So if we put this all together, we will print out the installed "pry-theme.rb" file with the addition in it.

ruby -p -e 'puts "Pry.config.hooks" if /Pry\.config/' `gem which pry-theme`

Editing the original file

It's never a great solution to edit your installed gems directly, obviously, but I figured it's a simple enough way to show you what should fix it so you could decide if you wanted to do that. I started to do it myself and send a PR, but just wasn't sure how to show it for a test, given that it's all editing these global variables (this is what a constant is, after all) that will become correct over time anyway.

So, I figured you could try in your env, see it's broken, run that code to add the extra line, see it's fixed, and then decide what to do. It seemed easier to give it in a 1-liner than have a long explanation of what code to edit, how, where, and so on, but in retrospect, I might have been wrong :P

Anyway, the way we edit the file itself instead of printing it to the console like we are currently doing, is to add the -i flag, which turns on "in-place-edit-mode", basically meaning that whatever the script prints out will replace the contents of the file (docs are in the man pages: man ruby | col -b | ruby -ne 'print if /^\s*-i/../\s*(-l)/ and !$1'). So, we add the -i flag:

ruby -p -i -e 'puts "Pry.config.hooks" if /Pry\.config/' `gem which pry-theme`

And now, we've added the fix to the installed gem, so we can try it out easily, see that it works, run gem pristine pry-theme to revert, see that it is broken again. And decide if we want to put it into the lib and release a new version.

Cheers :beers:, hope that wasn't too long!

kyrylo commented 10 years ago

Thanks, man! This is some serious hackery. I learnt a lot of things from your post. I understand now. I'm probably going to release a new version with just that fix, because only goodness knows when the new version of Pry will be out.

kyrylo commented 10 years ago

Feel free to send a pull request, if you wish.