hairballs 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4d0f86e9c3d02f22b832c4b3edce907001d0db2f
4
- data.tar.gz: 7ddc281fd14c1d9c673b59bd6ca1f218e1722f2a
3
+ metadata.gz: d253d151df5fdf784c216a8785627d1f0881cb01
4
+ data.tar.gz: 45bce4a52cd3d2e01f48a3765b9fef39fffb36bc
5
5
  SHA512:
6
- metadata.gz: 0ed4bf7812d457c37d006c4b6b065a6a05df37aba2991f77fa261aa2939bc51ef1df35a55d861a75b5fc93ffe556d4a102a618f99f84dc4126a174679fa4311b
7
- data.tar.gz: 11bf1690a4fd0c528223c4608bbc757a17720f64dfdc137ffe58abae6e505499c790e32c711203f2d768fabfe09900b6c0f6b9872dbb5da9539e50164f211c53
6
+ metadata.gz: 0ca0f9c162b224b218184fd8afd15731ed52d220ff24032e75896cca7ed3bae272e6da15016f2556cbdcf7ec251e0dddbc01361b5dfd2f6fe1db076dadf1d3ff
7
+ data.tar.gz: baff3f4a22ebfe513bba046a54486bf67da351bee1b8ea7f4365a7a21d9ef7e7f8c63f74775cb0c109b756fce5d28aae93389e368647dee838bb8e00fe38e8a1
data/History.md CHANGED
@@ -1,3 +1,14 @@
1
+ ### 0.1.0 / 2015-02-18
2
+
3
+ * Improvements
4
+ * Added `Hairballs.project_root`, which tries to determine the root
5
+ directory for the project you're working in.
6
+ * Refactored configuration to Hairballs::Configuration.
7
+ * Bug Fixes
8
+ * Fixed nested file completion for the `tab_completion_for_files` plugin.
9
+ * Fixed `Hairballs::LibraryHelpers#find_latest_gem` to find the latest
10
+ instead of the earliest.
11
+
1
12
  ### 0.0.1 / 2014-12-19
2
13
 
3
14
  * Happy Birthday!
data/README.md CHANGED
@@ -105,10 +105,10 @@ end
105
105
  ```ruby
106
106
  # hairballs/themes/turboladen_rails.rb
107
107
  Hairballs.add_theme(:turboladen_rails) do |theme|
108
- theme.libraries do
109
- libs_to_require = %w(irb/completion looksee wirble awesome_print)
108
+ theme.libraries do |libs|
109
+ libs += %w(irb/completion looksee wirble awesome_print)
110
110
 
111
- libs_to_require +
111
+ libs +=
112
112
  case RUBY_PLATFORM
113
113
  when /mswin32|mingw32/
114
114
  %w(win32console)
data/hairballs.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ['Steve Loveless']
10
10
  spec.email = ['steve.loveless@gmail.com']
11
11
  spec.summary = 'Like oh-my-zsh, but for IRB.'
12
- spec.description = 'Some tools for making customizing your IRB sessions a little easier.'
12
+ spec.description = spec.summary
13
13
  spec.homepage = 'https://github.com/turboladen/hairballs'
14
14
  spec.license = 'MIT'
15
15
 
@@ -0,0 +1,170 @@
1
+ require 'open3'
2
+ require 'pathname'
3
+ require 'ostruct'
4
+ require 'hairballs/ext/kernel_vputs'
5
+ require 'hairballs/exceptions'
6
+ require 'hairballs/theme'
7
+ require 'hairballs/plugin'
8
+ require 'hairballs/version'
9
+
10
+ class Hairballs
11
+ class Configuration
12
+ # @return [Array<Hairballs::Theme>]
13
+ attr_reader :themes
14
+
15
+ # @return [Hairballs::Theme]
16
+ attr_reader :current_theme
17
+
18
+ # All Hairballs::Plugins available to be loaded.
19
+ #
20
+ # @return [Array<Hairballs::Plugin>]
21
+ attr_reader :plugins
22
+
23
+ # All Hairballs::Plugins that have been loaded.
24
+ #
25
+ # @return [Array<Hairballs::Plugin>]
26
+ attr_reader :loaded_plugins
27
+
28
+ # Used for maintaining all possible completion Procs, thus allowing many
29
+ # different plugins to define a Proc for completion without overriding Procs
30
+ # defined for other plugins.
31
+ #
32
+ # @return [Array<Proc>]
33
+ attr_reader :completion_procs
34
+
35
+ # @return [String]
36
+ attr_reader :project_name
37
+
38
+ # @return [String]
39
+ attr_reader :project_root
40
+
41
+ def initialize
42
+ @themes = []
43
+ @current_theme = nil
44
+ @plugins = []
45
+ @loaded_plugins = []
46
+ @completion_procs = []
47
+ @project_name = nil
48
+ @project_root = nil
49
+ end
50
+
51
+ # @return [String]
52
+ def version
53
+ Hairballs::VERSION
54
+ end
55
+
56
+ # Is IRB getting loaded for a rails console?
57
+ #
58
+ # @return [Boolean]
59
+ def rails?
60
+ ENV.has_key?('RAILS_ENV') || !!defined?(Rails)
61
+ end
62
+
63
+ # Name of the relative directory.
64
+ #
65
+ # @return [String]
66
+ def project_name
67
+ @project_name ||= File.basename(project_root)
68
+ end
69
+
70
+ def project_root
71
+ @project_root ||= find_project_root
72
+ end
73
+
74
+ def project_root?(path)
75
+ File.expand_path(path) == project_root
76
+ end
77
+
78
+ # Builds a new Hairballs::Theme and adds it to the list of `.themes` that
79
+ # can be used.
80
+ #
81
+ # @param [Symbol] name Name to give the new Theme.
82
+ # @return [Theme]
83
+ def add_theme(name)
84
+ theme = Theme.new(name)
85
+
86
+ yield theme
87
+
88
+ themes << theme
89
+ vputs "Added theme: #{name}"
90
+
91
+ theme
92
+ end
93
+
94
+ # Tells IRB to use the Hairballs::Theme of +theme_name+.
95
+ #
96
+ # @param [Symbol] theme_name The name of the Theme to use/switch to.
97
+ def use_theme(theme_name)
98
+ switch_to = themes.find { |theme| theme.name == theme_name }
99
+ fail ThemeUseFailure.new(theme_name) unless switch_to
100
+ vputs "Switched to theme: #{theme_name}"
101
+
102
+ switch_to.use!
103
+ @current_theme = switch_to
104
+
105
+ true
106
+ end
107
+
108
+ # Builds a new Hairballs::Plugin and adds it to thelist of `.plugins` that
109
+ # can be used.
110
+ #
111
+ # @param [Symbol] name
112
+ # @param [Hash] options Plugin-dependent options to define. These get
113
+ # passed along the the Hairballs::Plugin object and are used as attributes
114
+ # of the plugin.
115
+ def add_plugin(name, **options)
116
+ plugin = Plugin.new(name, options)
117
+ yield plugin
118
+ plugins << plugin
119
+ vputs "Added plugin: #{name}"
120
+
121
+ plugin
122
+ end
123
+
124
+ # Searches for the Hairballs::Plugin by the +plugin_name+, then loads it.
125
+ # Raises
126
+ # @param plugin_name [Symbol]
127
+ def load_plugin(plugin_name, **options)
128
+ plugin_to_use = plugins.find { |plugin| plugin.name == plugin_name }
129
+ fail PluginNotFound.new(plugin_name) unless plugin_to_use
130
+ vputs "Using plugin: #{plugin_name}"
131
+
132
+ plugin_to_use.load!(options)
133
+ loaded_plugins << plugin_to_use
134
+
135
+ true
136
+ end
137
+
138
+ private
139
+
140
+ def find_project_root
141
+ if rails?
142
+ ::Rails.root
143
+ else
144
+ root_by_git || root_by_lib_dir
145
+ end
146
+ end
147
+
148
+ def root_by_git
149
+ _stdin, stdout, _stderr = Open3.popen3('git rev-parse --show-toplevel')
150
+
151
+ stdout.gets.strip
152
+ end
153
+
154
+ def root_by_lib_dir
155
+ cwd = Pathname.new(Dir.pwd)
156
+ root = nil
157
+
158
+ cwd.ascend do |dir|
159
+ lib_dir = File.join(dir.to_s, 'lib')
160
+
161
+ if dir.children.find { |c| c.to_s =~ /#{lib_dir}/ && File.exist?(lib_dir) }
162
+ root = dir.to_s
163
+ break
164
+ end
165
+ end
166
+
167
+ root
168
+ end
169
+ end
170
+ end
@@ -1,3 +1,5 @@
1
+ require 'hairballs/ext/kernel_vputs'
2
+
1
3
  class Hairballs
2
4
  # Helpers specifying and requiring dependencies for Themes and Plugins.
3
5
  module LibraryHelpers
@@ -5,14 +7,11 @@ class Hairballs
5
7
  def libraries(libs=nil)
6
8
  return @libraries if @libraries && libs.nil?
7
9
 
8
- @libraries = block_given? ? yield : libs
9
-
10
- unless @libraries.is_a?(Array)
11
- fail ArgumentError,
12
- "Block must return an Array but returned #{@libraries}."
10
+ @libraries = if libs
11
+ libs
12
+ else
13
+ yield([])
13
14
  end
14
-
15
- @libraries
16
15
  end
17
16
 
18
17
  # Requires #libraries on load. If they're not installed, install them. If
@@ -43,10 +42,14 @@ class Hairballs
43
42
  end
44
43
  end
45
44
 
45
+ # Path to the highest version of the gem with the given gem.
46
+ #
47
+ # @param [String] gem_name
48
+ # @return [String]
46
49
  def find_latest_gem(gem_name)
47
50
  the_gem = Dir.glob("#{Gem.dir}/gems/#{gem_name}-*")
48
51
 
49
- the_gem.empty? ? nil : the_gem.first
52
+ the_gem.empty? ? nil : the_gem.sort.last
50
53
  end
51
54
 
52
55
  # Add all gems in the global gemset to the $LOAD_PATH so they can be used
@@ -1,4 +1,5 @@
1
- require_relative 'library_helpers'
1
+ require 'hairballs/exceptions'
2
+ require 'hairballs/library_helpers'
2
3
 
3
4
  class Hairballs
4
5
  # Plugins provide means for adding functionality to your IRB sessions. They
@@ -63,12 +64,12 @@ class Hairballs
63
64
 
64
65
  require_libraries
65
66
 
66
- if @on_load
67
- if @on_load.kind_of?(Proc)
68
- @on_load.call
69
- else
70
- fail PluginLoadFailure, self.name
71
- end
67
+ return unless @on_load
68
+
69
+ if @on_load.kind_of?(Proc)
70
+ @on_load.call
71
+ else
72
+ fail PluginLoadFailure, self.name
72
73
  end
73
74
  end
74
75
  end
@@ -1,4 +1,4 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  Hairballs.add_plugin(:awesome_print) do |plugin|
4
4
  plugin.libraries %w(awesome_print)
@@ -1,4 +1,4 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  # When any value is returned by evaluating some Ruby, this will check if it is
4
4
  # JSON (by parsing it). If it's JSON-like, it will get formatted prettily and
@@ -1,4 +1,4 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  # Returns only the methods not present on basic Objects.
4
4
  #
@@ -1,4 +1,4 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  Hairballs.add_plugin(:irb_history, save_history: 1000, eval_history: 20, global_history_file: true) do |plugin|
4
4
  plugin.libraries %w(irb/ext/save-history)
@@ -1,4 +1,4 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  # Directly lifted from rbates/dotfiles! Adds +#ri+ to all Objects, letting you
4
4
  # get ri docs from within your IRB session.
@@ -1,4 +1,4 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  # Quick and dirty benchmarking of whatever block you pass to the method.
4
4
  #
@@ -1,4 +1,4 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  # Adds the Object#require_project_lib method as a shortcut for
4
4
  #
@@ -1,4 +1,4 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  # Adds the ability to tab-complete files that are in the current directory.
4
4
  #
@@ -9,10 +9,13 @@ require_relative '../../hairballs'
9
9
  # # Will complete like this...
10
10
  # irb> File.read("README.md"
11
11
  #
12
- Hairballs.add_plugin(:tab_completion_for_files) do |plugin|
12
+ # The +completion_append_character+ is really a Readline option that tells it
13
+ # what to do when you tab-complete a term. It's set to not add anything to the
14
+ # completed term, but you may find it suits you better to append a single space.
15
+ Hairballs.add_plugin(:tab_completion_for_files, completion_append_character: nil) do |plugin|
13
16
  plugin.on_load do
14
17
  Hairballs.completion_procs << proc do |string|
15
- Dir['*'].grep(/^#{Regexp.escape(string)}*/)
18
+ Dir[string + '*'].grep(/^#{Regexp.escape(string)}/)
16
19
  end
17
20
 
18
21
  if defined? ::IRB::InputCompletor::CompletionProc
@@ -25,11 +28,12 @@ Hairballs.add_plugin(:tab_completion_for_files) do |plugin|
25
28
  end.flatten.uniq
26
29
  end
27
30
 
28
- if Readline.respond_to?('basic_word_break_characters=')
29
- Readline.basic_word_break_characters= " \"'\t\n`><=;|&{("
31
+ if Readline.respond_to?(:basic_word_break_characters=)
32
+ original_breaks = Readline.basic_word_break_characters
33
+ Readline.basic_word_break_characters = " \"'#{original_breaks}"
30
34
  end
31
35
 
32
- Readline.completion_append_character = nil
36
+ Readline.completion_append_character = plugin.completion_append_character
33
37
  Readline.completion_proc = completion_proc
34
38
  end
35
39
  end
@@ -1,4 +1,4 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  # Just loads Wirble.
4
4
  Hairballs.add_plugin(:wirble) do |plugin|
@@ -1,5 +1,5 @@
1
- require_relative 'library_helpers'
2
- require_relative 'prompt'
1
+ require 'hairballs/library_helpers'
2
+ require 'hairballs/prompt'
3
3
 
4
4
  class Hairballs
5
5
  # Themes primarily provide a means for customizing the look of your IRB
@@ -10,7 +10,7 @@ class Hairballs
10
10
  # +Hairballs.add_theme()+ and +Hairballs.use_theme()+ should cover most use
11
11
  # cases.
12
12
  class Theme
13
- include LibraryHelpers
13
+ include Hairballs::LibraryHelpers
14
14
 
15
15
  # Just an identifier for the Theme. Don't name two themes the same
16
16
  # name--that will cause problems.
@@ -97,7 +97,6 @@ class Hairballs
97
97
  end
98
98
 
99
99
  def set_up_pry_printer
100
- puts "@pompt return format: #{@prompt.return_format}"
101
100
  if @prompt.return_format
102
101
  Pry.config.print = proc do |output, value|
103
102
  output.printf @prompt.return_format, value.inspect
@@ -1,14 +1,14 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  Hairballs.add_theme(:turboladen) do |theme|
4
- theme.libraries do
5
- libs_to_require = %w(
4
+ theme.libraries do |libs_to_require|
5
+ libs_to_require += %w(
6
6
  irb/completion
7
7
  looksee
8
8
  colorize
9
9
  )
10
10
 
11
- libs_to_require +
11
+ libs_to_require +=
12
12
  case RUBY_PLATFORM
13
13
  when /mswin32|mingw32/
14
14
  %w(win32console)
@@ -1,14 +1,14 @@
1
- require_relative '../../hairballs'
1
+ require 'hairballs'
2
2
 
3
3
  Hairballs.add_theme(:turboladen_rails) do |theme|
4
- theme.libraries do
5
- libs_to_require = %w(
4
+ theme.libraries do |libs_to_require|
5
+ libs_to_require += %w(
6
6
  irb/completion
7
7
  looksee
8
8
  colorize
9
9
  )
10
10
 
11
- libs_to_require +
11
+ libs_to_require +=
12
12
  case RUBY_PLATFORM
13
13
  when /mswin32|mingw32/
14
14
  %w(win32console)
@@ -1,3 +1,3 @@
1
1
  class Hairballs
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
data/lib/hairballs.rb CHANGED
@@ -1,113 +1,33 @@
1
- require_relative 'hairballs/ext/kernel_vputs'
2
- require_relative 'hairballs/exceptions'
3
- require_relative 'hairballs/theme'
4
- require_relative 'hairballs/plugin'
5
- require_relative 'hairballs/version'
1
+ require 'forwardable'
2
+ require 'hairballs/version'
3
+ require 'hairballs/configuration'
6
4
 
7
5
  # Home of the Hairballs DSL for defining and using Themes and Plugins.
8
6
  class Hairballs
9
- class << self
10
- # @return [Hairballs::Theme]
11
- attr_reader :current_theme
12
-
13
- # @return [Array<Hairballs::Theme>]
14
- def themes
15
- @themes ||= []
16
- end
17
-
18
- # Builds a new Hairballs::Theme and adds it to the list of `.themes` that
19
- # can be used.
20
- #
21
- # @param name [Symbol] Name to give the new Theme.
22
- # @return [Theme]
23
- def add_theme(name)
24
- theme = Theme.new(name)
25
- yield theme
26
- themes << theme
27
- vputs "Added theme: #{name}"
28
-
29
- theme
30
- end
31
-
32
- # Tells IRB to use the Hairballs::Theme of +theme_name+.
33
- #
34
- # @param theme_name [Symbol] The name of the Theme to use/switch to.
35
- def use_theme(theme_name)
36
- switch_to = themes.find { |theme| theme.name == theme_name }
37
- fail ThemeUseFailure.new(theme_name) unless switch_to
38
- vputs "Switched to theme: #{theme_name}"
39
-
40
- switch_to.use!
41
- @current_theme = switch_to
42
-
43
- true
44
- end
45
-
46
- # All Hairballs::Plugins available to be loaded.
47
- #
48
- # @return [Array<Hairballs::Plugin>]
49
- def plugins
50
- @plugins ||= []
51
- end
52
-
53
- # All Hairballs::Plugins that have been loaded.
54
- #
55
- # @return [Array<Hairballs::Plugin>]
56
- def loaded_plugins
57
- @loaded_plugins ||= []
58
- end
59
-
60
- # Builds a new Hairballs::Plugin and adds it to thelist of `.plugins` that
61
- # can be used.
62
- #
63
- # @param name [Symbol]
64
- # @param options [Hash] Plugin-dependent options to define. These get
65
- # passed along the the Hairballs::Plugin object and are used as attributes
66
- # of the plugin.
67
- def add_plugin(name, **options)
68
- plugin = Plugin.new(name, options)
69
- yield plugin
70
- plugins << plugin
71
- vputs "Added plugin: #{name}"
72
-
73
- plugin
74
- end
75
-
76
- # Searches for the Hairballs::Plugin by the +plugin_name+, then loads it.
77
- # Raises
78
- # @param plugin_name [Symbol]
79
- def load_plugin(plugin_name, **options)
80
- plugin_to_use = plugins.find { |plugin| plugin.name == plugin_name }
81
- fail PluginNotFound.new(plugin_name) unless plugin_to_use
82
- vputs "Using plugin: #{plugin_name}"
7
+ # @return [Hairballs::Configuration]
8
+ def self.config
9
+ @@config ||= Hairballs::Configuration.new
10
+ end
83
11
 
84
- plugin_to_use.load!(options)
85
- loaded_plugins << plugin_to_use
12
+ class << self
13
+ extend Forwardable
86
14
 
87
- true
88
- end
15
+ def_delegators :config,
16
+ :themes,
17
+ :add_theme,
18
+ :current_theme,
19
+ :use_theme,
89
20
 
90
- # Name of the relative directory.
91
- #
92
- # @return [String]
93
- def project_name
94
- @project_name ||= File.basename(Dir.pwd)
95
- end
21
+ :plugins,
22
+ :load_plugin,
23
+ :loaded_plugins,
24
+ :add_plugin,
96
25
 
97
- # Is IRB getting loaded for a rails console?
98
- #
99
- # @return [Boolean]
100
- def rails?
101
- ENV.has_key?('RAILS_ENV') || !!defined?(Rails)
102
- end
26
+ :completion_procs,
103
27
 
104
- # Used for maintaining all possible completion Procs, thus allowing many
105
- # different plugins to define a Proc for completion without overriding Procs
106
- # defined for other plugins.
107
- #
108
- # @return [Array<Proc>]
109
- def completion_procs
110
- @completion_procs ||= []
111
- end
28
+ :project_name,
29
+ :project_root,
30
+ :version,
31
+ :rails?
112
32
  end
113
33
  end
@@ -0,0 +1,195 @@
1
+ require 'spec_helper'
2
+ require 'hairballs/configuration'
3
+
4
+ RSpec.describe Hairballs::Configuration do
5
+ subject(:config) { described_class.new }
6
+
7
+ describe '#themes' do
8
+ subject { config.themes }
9
+ it { is_expected.to be_an Array }
10
+ it { is_expected.to be_empty }
11
+ end
12
+
13
+ describe '#add_theme' do
14
+ let(:theme) { double 'Hairballs::Theme' }
15
+
16
+ context 'block given and name param is a Symbol' do
17
+ before do
18
+ expect(Hairballs::Theme).to receive(:new).with(:test).and_return theme
19
+ end
20
+
21
+ it 'yields the Theme' do
22
+ expect { |b| subject.add_theme(:test, &b) }.to yield_with_args(theme)
23
+ end
24
+
25
+ it 'adds the Theme to @themes' do
26
+ expect(subject.themes).to receive(:<<).with(theme)
27
+ subject.add_theme(:test) { |_| }
28
+ end
29
+
30
+ it 'returns the Theme' do
31
+ expect(subject.add_theme(:test) { |_| }).to eq theme
32
+ end
33
+ end
34
+
35
+ context 'no block given' do
36
+ before do
37
+ allow(Hairballs::Theme).to receive(:new).and_return theme
38
+ end
39
+
40
+ it 'raises a LocalJumpError' do
41
+ expect { subject.add_theme(:test) }.to raise_exception(LocalJumpError)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe '#use_theme' do
47
+ let(:theme) { double 'Hairballs::Theme', name: :test }
48
+
49
+ context 'theme_name represents an added theme' do
50
+ before do
51
+ expect(subject.themes).to receive(:find).and_return theme
52
+ end
53
+
54
+ it 'does not raise a ThemeUseFailure' do
55
+ allow(theme).to receive(:use!)
56
+ expect { subject.use_theme(:test) }.to_not raise_exception
57
+ end
58
+
59
+ it 'tells the theme to #use!' do
60
+ expect(theme).to receive(:use!)
61
+
62
+ subject.use_theme(:test)
63
+ end
64
+
65
+ it 'sets @current_theme to the new theme' do
66
+ allow(theme).to receive(:use!)
67
+
68
+ expect { subject.use_theme(:test) }.
69
+ to change { subject.instance_variable_get(:@current_theme) }.
70
+ to(theme)
71
+ end
72
+ end
73
+
74
+ context 'theme_name does not represent an added theme' do
75
+ it 'raises a ThemeUseFailure' do
76
+ expect(subject.themes).to receive(:find).and_return nil
77
+
78
+ expect do
79
+ subject.use_theme(:meow)
80
+ end.to raise_exception(Hairballs::ThemeUseFailure)
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#plugins' do
86
+ subject { config.plugins }
87
+ it { is_expected.to be_an Array }
88
+ end
89
+
90
+ describe '#loaded_plugins' do
91
+ subject { config.loaded_plugins }
92
+ it { is_expected.to be_an Array }
93
+ end
94
+
95
+ describe '#add_plugin' do
96
+ let(:plugin) { double 'Hairballs::Plugin' }
97
+
98
+ context 'block given and name param is a Symbol' do
99
+ before do
100
+ expect(Hairballs::Plugin).to receive(:new).with(:test, {}).and_return plugin
101
+ end
102
+
103
+ it 'yields the Plugin' do
104
+ expect { |b| subject.add_plugin(:test, &b) }.to yield_with_args(plugin)
105
+ end
106
+
107
+ it 'adds the Plugin to @plugins' do
108
+ expect(subject.plugins).to receive(:<<).with(plugin)
109
+ subject.add_plugin(:test) { |_| }
110
+ end
111
+
112
+ it 'returns the Plugin' do
113
+ expect(subject.add_plugin(:test) { |_| }).to eq plugin
114
+ end
115
+ end
116
+
117
+ context 'no block given' do
118
+ before do
119
+ allow(Hairballs::Plugin).to receive(:new).and_return plugin
120
+ end
121
+
122
+ it 'raises a LocalJumpError' do
123
+ expect { subject.add_plugin(:test) }.to raise_exception(LocalJumpError)
124
+ end
125
+ end
126
+ end
127
+
128
+ describe '#load_plugin' do
129
+ let(:plugin) { double 'Hairballs::Plugin', name: :test }
130
+
131
+ context 'theme_name represents an added plugin' do
132
+ before do
133
+ expect(subject.plugins).to receive(:find).and_return plugin
134
+ end
135
+
136
+ it 'does not raise an exception' do
137
+ allow(plugin).to receive(:load!)
138
+
139
+ expect do
140
+ subject.load_plugin(:test)
141
+ end.to_not raise_exception
142
+ end
143
+
144
+ it 'tells the plugin to #load!' do
145
+ expect(plugin).to receive(:load!)
146
+ subject.load_plugin(:test)
147
+ end
148
+
149
+ it 'updates @loaded_plugins with the new theme' do
150
+ allow(plugin).to receive(:load!)
151
+
152
+ expect { subject.load_plugin(:test) }.
153
+ to change { subject.loaded_plugins.size }.
154
+ by(1)
155
+ end
156
+ end
157
+
158
+ context 'plugin_name does not represent an added plugin' do
159
+ it 'raises a PluginNotFound' do
160
+ expect do
161
+ subject.load_plugin(:meow)
162
+ end.to raise_exception(Hairballs::PluginNotFound)
163
+ end
164
+ end
165
+ end
166
+
167
+ describe '.project_name' do
168
+ subject { config.project_name }
169
+ it { is_expected.to eq 'hairballs' }
170
+ end
171
+
172
+ describe '.project_root' do
173
+ before do
174
+ allow(Dir).to receive(:pwd).and_return '/meow/hairballs'
175
+ end
176
+
177
+ subject { config.project_name }
178
+ end
179
+
180
+ describe '.rails?' do
181
+ subject { config.rails? }
182
+
183
+ context 'not using Rails' do
184
+ it { is_expected.to eq false }
185
+ end
186
+
187
+ context 'using Rails' do
188
+ context 'RAILS_ENV is defined' do
189
+ before { ENV['RAILS_ENV'] = 'blargh' }
190
+ after { ENV.delete('RAILS_ENV') }
191
+ it { is_expected.to eq true }
192
+ end
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'hairballs/library_helpers'
3
+
4
+ RSpec.describe Hairballs::LibraryHelpers do
5
+ subject { Object.new.extend described_class }
6
+
7
+ describe '#libraries' do
8
+ context 'block given' do
9
+ it 'yields an empty array' do
10
+ expect { |b| subject.libraries(&b) }.to yield_with_args([])
11
+ end
12
+
13
+ it 'allows adding to the yielded array' do
14
+ expect {
15
+ subject.libraries do |libs|
16
+ libs << 'meow'
17
+ end
18
+ }.to change { subject.instance_variable_get(:@libraries) }.
19
+ from(nil).to(['meow'])
20
+ end
21
+ end
22
+
23
+ context 'block not given' do
24
+ it 'sets @libraries to the given param' do
25
+ expect {
26
+ subject.libraries(['meow'])
27
+ }.to change { subject.instance_variable_get(:@libraries) }.
28
+ from(nil).to(['meow'])
29
+ end
30
+ end
31
+
32
+ context 'block AND param given' do
33
+ it 'sets @libraries to the param value' do
34
+ expect {
35
+ subject.libraries(['meow'])
36
+ }.to change { subject.instance_variable_get(:@libraries) }.
37
+ from(nil).to(['meow'])
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '#require_libraries' do
43
+ context '@libraries is nil' do
44
+ it 'returns nil' do
45
+ expect(subject.require_libraries).to be_nil
46
+ end
47
+ end
48
+
49
+ context '@libraries is not nil' do
50
+ before do
51
+ subject.instance_variable_set(:@libraries, %w(one))
52
+ allow(subject).to receive(:vputs)
53
+ Hairballs.define_singleton_method(:rails?) { nil }
54
+ end
55
+
56
+ context 'libraries are not installed' do
57
+ it 'tries two times to require then Gem.install' do
58
+ expect(subject).to receive(:require).with('one').exactly(2).times.and_raise LoadError
59
+ expect(Gem).to receive(:install).with('one').exactly(1).times
60
+
61
+ expect { subject.require_libraries }.to raise_exception LoadError
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#find_latest_gem' do
68
+ it 'returns the path to the latest version of the gem' do
69
+ expect(subject.find_latest_gem('rake')).to match %r{gems/rake}
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+ require 'hairballs/plugin'
3
+
4
+ RSpec.describe Hairballs::Plugin do
5
+ subject { described_class.new('test', one: 1, two: 2) }
6
+
7
+ describe '#initialize' do
8
+ context 'with attributes' do
9
+ it 'defines getters and setters for each attribute' do
10
+ expect(subject.one).to eq 1
11
+ subject.one = 1.1
12
+ expect(subject.one).to eq 1.1
13
+
14
+ expect(subject.two).to eq 2
15
+ subject.two = 2.2
16
+ expect(subject.two).to eq 2.2
17
+ end
18
+ end
19
+ end
20
+
21
+ describe '#on_load' do
22
+ let(:the_block) { proc { puts 'hi' } }
23
+
24
+ it 'stores the given block' do
25
+ expect {
26
+ subject.on_load(&the_block)
27
+ }.to change { subject.instance_variable_get(:@on_load) }.
28
+ from(nil).to(the_block)
29
+ end
30
+ end
31
+
32
+ describe '#load!' do
33
+ context 'with attributes' do
34
+ it 'sets the attributes' do
35
+ expect(subject).to receive(:one=).with('thing one')
36
+ expect(subject).to receive(:two=).with('thing two')
37
+ allow(subject).to receive(:require_libraries)
38
+
39
+ subject.load! one: 'thing one', two: 'thing two'
40
+ end
41
+ end
42
+
43
+ context 'without attributes' do
44
+ it 'does not set the attributes' do
45
+ expect(subject).to_not receive(:one=)
46
+ expect(subject).to_not receive(:two=)
47
+ allow(subject).to receive(:require_libraries)
48
+
49
+ subject.load!
50
+ end
51
+ end
52
+
53
+ context 'with @on_load set to a Proc' do
54
+ let(:on_load) { double 'Proc', :kind_of? => true }
55
+ before { subject.instance_variable_set(:@on_load, on_load) }
56
+
57
+ it 'calls the on_load Proc' do
58
+ expect(on_load).to receive(:call)
59
+ subject.load!
60
+ end
61
+ end
62
+
63
+ context 'with @on_load set to not a Proc' do
64
+ let(:on_load) { double 'Proc', :kind_of? => false }
65
+ before { subject.instance_variable_set(:@on_load, on_load) }
66
+
67
+ it 'raises a PluginLoadFailure' do
68
+ expect { subject.load! }.to raise_exception Hairballs::PluginLoadFailure
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+ require 'hairballs/theme'
3
+
4
+ RSpec.describe Hairballs::Theme do
5
+ subject(:theme) { described_class.new(:test) }
6
+
7
+ describe '#irb_name' do
8
+ subject { theme.irb_name }
9
+ it { is_expected.to eq :TEST }
10
+ end
11
+ end
@@ -2,184 +2,28 @@ require 'spec_helper'
2
2
  require 'hairballs'
3
3
 
4
4
  describe Hairballs do
5
- subject { described_class }
5
+ subject(:hairballs) { described_class }
6
6
 
7
- describe '.themes' do
8
- subject { described_class.themes }
9
- it { is_expected.to be_an Array }
7
+ describe '.config' do
8
+ subject { hairballs.config }
9
+ it { is_expected.to be_a Hairballs::Configuration }
10
10
  end
11
11
 
12
- describe '.add_theme' do
13
- let(:theme) { double 'Hairballs::Theme' }
14
- context 'block given and name param is a Symbol' do
15
- before do
16
- expect(Hairballs::Theme).to receive(:new).with(:test).and_return theme
17
- end
12
+ it { is_expected.to respond_to(:themes) }
13
+ it { is_expected.to respond_to(:current_theme) }
14
+ it { is_expected.to respond_to(:add_theme) }
15
+ it { is_expected.to respond_to(:use_theme) }
18
16
 
19
- it 'yields the Theme' do
20
- expect { |b| subject.add_theme(:test, &b) }.to yield_with_args(theme)
21
- end
17
+ it { is_expected.to respond_to(:plugins) }
18
+ it { is_expected.to respond_to(:loaded_plugins) }
19
+ it { is_expected.to respond_to(:add_plugin) }
20
+ it { is_expected.to respond_to(:load_plugin) }
22
21
 
23
- it 'adds the Theme to @themes' do
24
- expect(subject.themes).to receive(:<<).with(theme)
25
- subject.add_theme(:test) { |_| }
26
- end
22
+ it { is_expected.to respond_to(:completion_procs) }
27
23
 
28
- it 'returns the Theme' do
29
- expect(subject.add_theme(:test) { |_| }).to eq theme
30
- end
31
- end
24
+ it { is_expected.to respond_to(:project_name) }
25
+ it { is_expected.to respond_to(:project_root) }
26
+ it { is_expected.to respond_to(:rails?) }
32
27
 
33
- context 'no block given' do
34
- before do
35
- allow(Hairballs::Theme).to receive(:new).and_return theme
36
- end
37
-
38
- it 'raises a LocalJumpError' do
39
- expect { subject.add_theme(:test) }.to raise_exception(LocalJumpError)
40
- end
41
- end
42
- end
43
-
44
- describe '.use_theme' do
45
- let(:theme) { double 'Hairballs::Theme', name: :test }
46
-
47
- context 'theme_name represents an added theme' do
48
- before(:example) do
49
- expect(subject.themes).to receive(:find).and_return theme
50
- end
51
-
52
- it 'does not raise a ThemeUseFailure' do
53
- allow(theme).to receive(:use!)
54
-
55
- expect do
56
- subject.use_theme(:test)
57
- end.to_not raise_exception
58
- end
59
-
60
- it 'tells the theme to #use!' do
61
- expect(theme).to receive(:use!)
62
- subject.use_theme(:test)
63
- end
64
-
65
- it 'sets @current_theme to the new theme' do
66
- allow(theme).to receive(:use!)
67
-
68
- expect { subject.use_theme(:test) }.
69
- to change { subject.instance_variable_get(:@current_theme) }.
70
- to(theme)
71
- end
72
- end
73
-
74
- context 'theme_name does not represent an added theme' do
75
- it 'raises a ThemeUseFailure' do
76
- expect do
77
- described_class.use_theme(:meow)
78
- end.to raise_exception(Hairballs::ThemeUseFailure)
79
- end
80
- end
81
- end
82
-
83
- describe '.plugins' do
84
- subject { described_class.plugins }
85
- it { is_expected.to be_an Array }
86
- end
87
-
88
- describe '.loaded_plugins' do
89
- subject { described_class.loaded_plugins }
90
- it { is_expected.to be_an Array }
91
- end
92
-
93
- describe '.add_plugin' do
94
- let(:plugin) { double 'Hairballs::Plugin' }
95
-
96
- context 'block given and name param is a Symbol' do
97
- before do
98
- expect(Hairballs::Plugin).to receive(:new).with(:test, {}).and_return plugin
99
- end
100
-
101
- it 'yields the Plugin' do
102
- expect { |b| subject.add_plugin(:test, &b) }.to yield_with_args(plugin)
103
- end
104
-
105
- it 'adds the Plugin to @plugins' do
106
- expect(subject.plugins).to receive(:<<).with(plugin)
107
- subject.add_plugin(:test) { |_| }
108
- end
109
-
110
- it 'returns the Plugin' do
111
- expect(subject.add_plugin(:test) { |_| }).to eq plugin
112
- end
113
- end
114
-
115
- context 'no block given' do
116
- before do
117
- allow(Hairballs::Plugin).to receive(:new).and_return plugin
118
- end
119
-
120
- it 'raises a LocalJumpError' do
121
- expect { subject.add_plugin(:test) }.to raise_exception(LocalJumpError)
122
- end
123
- end
124
- end
125
-
126
- describe '.load_plugin' do
127
- let(:plugin) { double 'Hairballs::Plugin', name: :test }
128
-
129
- context 'theme_name represents an added plugin' do
130
- before(:example) do
131
- expect(subject.plugins).to receive(:find).and_return plugin
132
- end
133
-
134
- it 'does not raise an exception' do
135
- allow(plugin).to receive(:load!)
136
-
137
- expect do
138
- subject.load_plugin(:test)
139
- end.to_not raise_exception
140
- end
141
-
142
- it 'tells the plugin to #load!' do
143
- expect(plugin).to receive(:load!)
144
- subject.load_plugin(:test)
145
- end
146
-
147
- it 'updates @loaded_plugins with the new theme' do
148
- allow(plugin).to receive(:load!)
149
-
150
- expect { subject.load_plugin(:test) }.
151
- to change { subject.loaded_plugins.size }.
152
- by(1)
153
- end
154
- end
155
-
156
- context 'plugin_name does not represent an added plugin' do
157
- it 'raises a PluginNotFound' do
158
- expect do
159
- described_class.load_plugin(:meow)
160
- end.to raise_exception(Hairballs::PluginNotFound)
161
- end
162
- end
163
- end
164
-
165
- describe '.project_name' do
166
- subject { described_class.project_name }
167
- it { is_expected.to eq 'hairballs' }
168
- end
169
-
170
- describe '.rails?' do
171
- subject { described_class.rails? }
172
-
173
- context 'not using Rails' do
174
- it { is_expected.to eq false }
175
- end
176
-
177
- context 'using Rails' do
178
- context 'RAILS_ENV is defined' do
179
- before { ENV['RAILS_ENV'] = 'blargh' }
180
- after { ENV.delete('RAILS_ENV') }
181
- it { is_expected.to eq true }
182
- end
183
- end
184
- end
28
+ it { is_expected.to respond_to(:version) }
185
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hairballs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Loveless
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-19 00:00:00.000000000 Z
11
+ date: 2015-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,7 +52,7 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.1'
55
- description: Some tools for making customizing your IRB sessions a little easier.
55
+ description: Like oh-my-zsh, but for IRB.
56
56
  email:
57
57
  - steve.loveless@gmail.com
58
58
  executables: []
@@ -68,6 +68,7 @@ files:
68
68
  - Rakefile
69
69
  - hairballs.gemspec
70
70
  - lib/hairballs.rb
71
+ - lib/hairballs/configuration.rb
71
72
  - lib/hairballs/exceptions.rb
72
73
  - lib/hairballs/ext/kernel_vputs.rb
73
74
  - lib/hairballs/library_helpers.rb
@@ -86,6 +87,10 @@ files:
86
87
  - lib/hairballs/themes/turboladen.rb
87
88
  - lib/hairballs/themes/turboladen_rails.rb
88
89
  - lib/hairballs/version.rb
90
+ - spec/hairballs/configuration_spec.rb
91
+ - spec/hairballs/library_helpers_spec.rb
92
+ - spec/hairballs/plugin_spec.rb
93
+ - spec/hairballs/theme_spec.rb
89
94
  - spec/hairballs_spec.rb
90
95
  - spec/spec_helper.rb
91
96
  homepage: https://github.com/turboladen/hairballs
@@ -108,11 +113,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
113
  version: '0'
109
114
  requirements: []
110
115
  rubyforge_project:
111
- rubygems_version: 2.2.0
116
+ rubygems_version: 2.2.2
112
117
  signing_key:
113
118
  specification_version: 4
114
119
  summary: Like oh-my-zsh, but for IRB.
115
120
  test_files:
121
+ - spec/hairballs/configuration_spec.rb
122
+ - spec/hairballs/library_helpers_spec.rb
123
+ - spec/hairballs/plugin_spec.rb
124
+ - spec/hairballs/theme_spec.rb
116
125
  - spec/hairballs_spec.rb
117
126
  - spec/spec_helper.rb
118
127
  has_rdoc: