homesick 1.1.6 → 2.0.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
- SHA1:
3
- metadata.gz: 883e37c1c9867b8620d8749c258607c19d35f887
4
- data.tar.gz: 5f88fd0008afdb5d8bd4100077eb3ce63be3d99d
2
+ SHA256:
3
+ metadata.gz: 197723e3c8d9b9d7f1d5b6c98361e990a604b0cd63795eca2712dfb41d6eabed
4
+ data.tar.gz: d7aa344ba47f9cdaa1502081c4dc6e6c9e917b5f5087716bb9d41bfec088ab02
5
5
  SHA512:
6
- metadata.gz: 0d983e5d652622d7fa93f02577186493271978cbfbcdbeffbb4409a2d064bf1a1985c6ca5cbcaec52adb088840ddd3e19d7de0e0e09630a06eb515ed3a614029
7
- data.tar.gz: '00119db9851844f54697fe5ee309b463cb37cf7d7e29226c728f0a4ef95b35cc898f11eaf13580297f0aa634f297013de32d82cccc8ad2cc4e45017fd1db5739'
6
+ metadata.gz: 5b1d9d3151de46356c7ed3126ee602e018a3774249370668c59d6e6b6f4d416193fdf0538bd076b94d7330b5a8e48ec9a4657dcb344d8f62de395e11d1533c00
7
+ data.tar.gz: 796965eaa00f961dc52735360b156084d1e51f47f65d76bd4d5dc98db75bd4813a966ca5ee247e884a941ab64344073c5ead85cdc53e1fcb9fd5a30fc3c89a1f
@@ -0,0 +1,9 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ groups:
8
+ development-dependencies:
9
+ dependency-type: development
@@ -0,0 +1,67 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ ruby-version: ['3.2', '3.3', '3.4']
15
+
16
+ steps:
17
+ - uses: actions/checkout@v5
18
+
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby-version }}
22
+ bundler-cache: true
23
+
24
+ - name: Configure git identity for specs
25
+ run: |
26
+ git config --global user.email "test@example.com"
27
+ git config --global user.name "Test User"
28
+
29
+ - name: Run tests
30
+ run: bundle exec rspec
31
+
32
+ - name: Run RuboCop
33
+ run: bundle exec rubocop
34
+
35
+ - name: Audit dependencies
36
+ run: |
37
+ bundle exec bundler-audit update
38
+ bundle exec bundler-audit check
39
+
40
+ mutant:
41
+ name: Mutation testing (changed code)
42
+ runs-on: ubuntu-latest
43
+ needs: test
44
+ # Only meaningful on PRs - --since compares against the base branch
45
+ if: github.event_name == 'pull_request'
46
+ # Non-blocking: results are informational; the nightly job is authoritative.
47
+ continue-on-error: true
48
+ timeout-minutes: 30
49
+
50
+ steps:
51
+ - uses: actions/checkout@v4
52
+ with:
53
+ # Full history is required so --since can resolve the base ref
54
+ fetch-depth: 0
55
+
56
+ - uses: ruby/setup-ruby@v1
57
+ with:
58
+ ruby-version: '3.3'
59
+ bundler-cache: true
60
+
61
+ - name: Configure git identity for specs
62
+ run: |
63
+ git config --global user.email "test@example.com"
64
+ git config --global user.name "Test User"
65
+
66
+ - name: Run mutation tests on changed code
67
+ run: bundle exec mutant run --since origin/${{ github.base_ref }}
@@ -0,0 +1,31 @@
1
+ name: Mutation Testing (full)
2
+
3
+ on:
4
+ # Run weekly on Sunday at 02:00 UTC
5
+ schedule:
6
+ - cron: '0 2 * * 0'
7
+ # Allow triggering manually from the Actions UI
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ mutant:
12
+ name: Full mutation coverage
13
+ runs-on: ubuntu-latest
14
+ # No hard timeout - the suite currently takes ~5 h; allow up to 6 h.
15
+ timeout-minutes: 360
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: '3.3'
23
+ bundler-cache: true
24
+
25
+ - name: Configure git identity for specs
26
+ run: |
27
+ git config --global user.email "test@example.com"
28
+ git config --global user.name "Test User"
29
+
30
+ - name: Run full mutation test suite
31
+ run: bundle exec mutant run
@@ -0,0 +1,27 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*.*.*'
7
+
8
+ jobs:
9
+ release:
10
+ name: Build and publish gem
11
+ runs-on: ubuntu-latest
12
+ environment: rubygems
13
+ permissions:
14
+ contents: read
15
+ # Required for RubyGems OIDC trusted publishing (no stored API key needed)
16
+ id-token: write
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: '3.3'
24
+ bundler-cache: true
25
+
26
+ - name: Build and push gem
27
+ uses: rubygems/release-gem@v1
data/.gitignore ADDED
@@ -0,0 +1,52 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # jeweler generated
12
+ pkg
13
+
14
+ .bundle
15
+
16
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
17
+ #
18
+ # * Create a file at ~/.gitignore
19
+ # * Include files you want ignored
20
+ # * Run: git config --global core.excludesfile ~/.gitignore
21
+ #
22
+ # After doing this, these files will be ignored in all your git projects,
23
+ # saving you from having to 'pollute' every project you touch with them
24
+ #
25
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
26
+ #
27
+ # For MacOS:
28
+ #
29
+ .DS_Store
30
+ #
31
+ # For TextMate
32
+ #*.tmproj
33
+ #tmtags
34
+ #
35
+ # For emacs:
36
+ *~
37
+ \#*
38
+ .\#*
39
+ #
40
+ # For vim:
41
+ *.swp
42
+ #
43
+ # For IDEA:
44
+ .idea/
45
+ *.iml
46
+
47
+ vendor/
48
+
49
+ homesick*.gem
50
+
51
+ # rbenv configuration
52
+ .ruby-version
data/.mutant.yml ADDED
@@ -0,0 +1,26 @@
1
+ # Mutant mutation testing configuration.
2
+ # Run with: mutant run [-- SubjectPattern]
3
+ # Examples:
4
+ # mutant run # all Homesick subjects
5
+ # mutant run -- Homesick::RC* # only the RC namespace
6
+ #
7
+ # This project is open source; the 'opensource' usage type is free.
8
+ usage: opensource
9
+
10
+ integration:
11
+ name: rspec
12
+
13
+ includes:
14
+ - lib
15
+
16
+ requires:
17
+ - homesick
18
+
19
+ matcher:
20
+ subjects:
21
+ - Homesick*
22
+
23
+ jobs: 4
24
+
25
+ mutation:
26
+ timeout: 30.0
data/.rubocop.yml CHANGED
@@ -1,19 +1,42 @@
1
- # TODO: Eval is required for the .homesickrc feature. This should eventually be
2
- # removed if the feature is implemented in a more secure way.
3
- Eval:
4
- Enabled: false
1
+ plugins:
2
+ - rubocop-rake
5
3
 
6
- # TODO: The following settings disable reports about issues that can be fixed
7
- # through refactoring. Remove these as offenses are removed from the code base.
4
+ AllCops:
5
+ NewCops: enable
6
+ TargetRubyVersion: 3.2
8
7
 
9
- ClassLength:
10
- Enabled: false
8
+ # Explicit maxes that reflect the current code. Reduce these incrementally
9
+ # as methods are refactored further.
11
10
 
12
- CyclomaticComplexity:
13
- Max: 13
11
+ Metrics/AbcSize:
12
+ Max: 35
14
13
 
15
- LineLength:
16
- Enabled: false
14
+ Metrics/BlockLength:
15
+ Exclude:
16
+ - 'spec/**/*'
17
17
 
18
- MethodLength:
19
- Max: 36
18
+ Metrics/ClassLength:
19
+ Max: 255
20
+
21
+ Metrics/CyclomaticComplexity:
22
+ Max: 10
23
+
24
+ Layout/LineLength:
25
+ Max: 120
26
+ Exclude:
27
+ - 'spec/**/*'
28
+
29
+ Metrics/MethodLength:
30
+ Max: 25
31
+
32
+ Metrics/ModuleLength:
33
+ Max: 210
34
+
35
+ Metrics/ParameterLists:
36
+ Max: 6
37
+
38
+ Metrics/PerceivedComplexity:
39
+ Max: 11
40
+
41
+ Gemspec/DevelopmentDependencies:
42
+ EnforcedStyle: gemspec
data/ChangeLog.markdown CHANGED
@@ -1,4 +1,31 @@
1
- #1.1.6
1
+ # 2.0.0
2
+
3
+ **Breaking changes** — see migration notes below before upgrading.
4
+
5
+ * Require Ruby >= 3.2; dropped support for Ruby 2.x and 3.0/3.1
6
+ * Pin Thor dependency to `~> 1.0`; Thor 0.x is no longer supported
7
+ * `.homesickrc` files must now use the `Homesick::RC::Context` DSL instead
8
+ of being evaluated in the CLI scope. Replace any direct CLI method calls
9
+ with the two DSL methods: `castle_path` (returns the castle's path) and
10
+ `run` (executes a shell command). See README for examples.
11
+ * `git clone` now respects the `--pretend` flag consistently with other actions
12
+ * Switch CI from Travis CI to GitHub Actions; added mutation testing, dependency
13
+ auditing, and automated gem release via RubyGems trusted publishing
14
+
15
+ **Migration from 1.x**
16
+
17
+ If your `.homesickrc` calls methods directly on the Homesick CLI object, update
18
+ it to use the new DSL. For example:
19
+
20
+ ```ruby
21
+ # Before (1.x)
22
+ FileUtils.ln_s "#{self.class.source_root}/file", "#{ENV['HOME']}/file"
23
+
24
+ # After (2.0)
25
+ run "ln -s #{castle_path}/file #{ENV['HOME']}/file"
26
+ ```
27
+
28
+ # 1.1.6
2
29
  * Makesure the FileUtils is imported correctly to avoid a potential error
3
30
  * Fixes an issue where comparing a diff would not use the content of the new file
4
31
  * Small documentation fixes
data/Gemfile CHANGED
@@ -1,36 +1,5 @@
1
- source 'https://rubygems.org'
2
-
3
- this_ruby = Gem::Version.new(RUBY_VERSION)
4
- ruby_230 = Gem::Version.new('2.3.0')
5
-
6
- # Add dependencies required to use your gem here.
7
- gem 'thor', '>= 0.14.0'
1
+ # frozen_string_literal: true
8
2
 
9
- # Add dependencies to develop your gem here.
10
- # Include everything needed to run rake, tests, features, etc.
11
- group :development do
12
- gem 'capture-output', '~> 1.0.0'
13
- gem 'coveralls', require: false
14
- gem 'guard'
15
- gem 'guard-rspec'
16
- gem 'jeweler', '>= 1.6.2', '< 2.2' if this_ruby < ruby_230
17
- gem 'jeweler', '>= 1.6.2' if this_ruby >= ruby_230
18
- gem 'rake', '>= 0.8.7'
19
- gem 'rb-readline', '~> 0.5.0'
20
- gem 'rspec', '~> 3.5.0'
21
- gem 'rubocop'
22
- gem 'test_construct'
23
-
24
- install_if -> { RUBY_PLATFORM =~ /linux|freebsd|openbsd|sunos|solaris/ } do
25
- gem 'libnotify'
26
- end
27
-
28
- install_if -> { RUBY_PLATFORM =~ /darwin/ } do
29
- gem 'terminal-notifier-guard', '~> 1.7.0'
30
- end
3
+ source 'https://rubygems.org'
31
4
 
32
- install_if -> { this_ruby < ruby_230 } do
33
- gem 'listen', '< 3'
34
- gem 'rack', '< 2'
35
- end
36
- end
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,128 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ homesick (2.0.0)
5
+ thor (~> 1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ addressable (2.8.9)
11
+ public_suffix (>= 2.0.2, < 8.0)
12
+ ast (2.4.3)
13
+ bigdecimal (4.0.1)
14
+ bundler-audit (0.9.3)
15
+ bundler (>= 1.2.0)
16
+ thor (~> 1.0)
17
+ capture-output (1.0.0)
18
+ date (3.5.1)
19
+ diff-lcs (1.6.2)
20
+ erb (6.0.2)
21
+ io-console (0.8.2)
22
+ irb (1.17.0)
23
+ pp (>= 0.6.0)
24
+ prism (>= 1.3.0)
25
+ rdoc (>= 4.0.0)
26
+ reline (>= 0.4.2)
27
+ json (2.19.2)
28
+ json-schema (6.2.0)
29
+ addressable (~> 2.8)
30
+ bigdecimal (>= 3.1, < 5)
31
+ language_server-protocol (3.17.0.5)
32
+ lint_roller (1.1.0)
33
+ mcp (0.8.0)
34
+ json-schema (>= 4.1)
35
+ mutant (0.15.1)
36
+ diff-lcs (>= 1.6, < 3)
37
+ irb (~> 1.15)
38
+ parser (~> 3.3.10)
39
+ regexp_parser (~> 2.10)
40
+ sorbet-runtime (~> 0.6.0)
41
+ unparser (~> 0.8.2)
42
+ mutant-rspec (0.15.1)
43
+ mutant (= 0.15.1)
44
+ rspec-core (>= 3.8.0, < 5.0.0)
45
+ parallel (1.27.0)
46
+ parser (3.3.10.2)
47
+ ast (~> 2.4.1)
48
+ racc
49
+ pp (0.6.3)
50
+ prettyprint
51
+ prettyprint (0.2.0)
52
+ prism (1.9.0)
53
+ psych (5.3.1)
54
+ date
55
+ stringio
56
+ public_suffix (7.0.5)
57
+ racc (1.8.1)
58
+ rainbow (3.1.1)
59
+ rake (13.3.1)
60
+ rdoc (7.2.0)
61
+ erb
62
+ psych (>= 4.0.0)
63
+ tsort
64
+ regexp_parser (2.11.3)
65
+ reline (0.6.3)
66
+ io-console (~> 0.5)
67
+ rspec (3.13.2)
68
+ rspec-core (~> 3.13.0)
69
+ rspec-expectations (~> 3.13.0)
70
+ rspec-mocks (~> 3.13.0)
71
+ rspec-core (3.13.6)
72
+ rspec-support (~> 3.13.0)
73
+ rspec-expectations (3.13.5)
74
+ diff-lcs (>= 1.2.0, < 2.0)
75
+ rspec-support (~> 3.13.0)
76
+ rspec-mocks (3.13.8)
77
+ diff-lcs (>= 1.2.0, < 2.0)
78
+ rspec-support (~> 3.13.0)
79
+ rspec-support (3.13.7)
80
+ rubocop (1.85.1)
81
+ json (~> 2.3)
82
+ language_server-protocol (~> 3.17.0.2)
83
+ lint_roller (~> 1.1.0)
84
+ mcp (~> 0.6)
85
+ parallel (~> 1.10)
86
+ parser (>= 3.3.0.2)
87
+ rainbow (>= 2.2.2, < 4.0)
88
+ regexp_parser (>= 2.9.3, < 3.0)
89
+ rubocop-ast (>= 1.49.0, < 2.0)
90
+ ruby-progressbar (~> 1.7)
91
+ unicode-display_width (>= 2.4.0, < 4.0)
92
+ rubocop-ast (1.49.1)
93
+ parser (>= 3.3.7.2)
94
+ prism (~> 1.7)
95
+ rubocop-rake (0.7.1)
96
+ lint_roller (~> 1.1)
97
+ rubocop (>= 1.72.1)
98
+ ruby-progressbar (1.13.0)
99
+ sorbet-runtime (0.6.13055)
100
+ stringio (3.2.0)
101
+ test_construct (2.0.2)
102
+ thor (1.5.0)
103
+ tsort (0.2.0)
104
+ unicode-display_width (3.2.0)
105
+ unicode-emoji (~> 4.1)
106
+ unicode-emoji (4.2.0)
107
+ unparser (0.8.2)
108
+ diff-lcs (>= 1.6, < 3)
109
+ parser (>= 3.3.0)
110
+ prism (>= 1.5.1)
111
+
112
+ PLATFORMS
113
+ ruby
114
+ x86_64-linux
115
+
116
+ DEPENDENCIES
117
+ bundler-audit (~> 0.9)
118
+ capture-output (~> 1.0)
119
+ homesick!
120
+ mutant-rspec
121
+ rake
122
+ rspec (~> 3.0)
123
+ rubocop
124
+ rubocop-rake
125
+ test_construct
126
+
127
+ BUNDLED WITH
128
+ 2.5.22
data/Guardfile CHANGED
@@ -1,6 +1,8 @@
1
- guard :rspec, :cmd => 'bundle exec rspec' do
1
+ # frozen_string_literal: true
2
+
3
+ guard :rspec, cmd: 'bundle exec rspec' do
2
4
  watch(%r{^spec/.+_spec\.rb$})
3
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
- watch(%r{^lib/homesick/.*\.rb}) { "spec" }
5
- watch('spec/spec_helper.rb') { "spec" }
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
6
+ watch(%r{^lib/homesick/.*\.rb}) { 'spec' }
7
+ watch('spec/spec_helper.rb') { 'spec' }
6
8
  end
data/README.markdown CHANGED
@@ -1,11 +1,7 @@
1
1
  # homesick
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/homesick.svg)](http://badge.fury.io/rb/homesick)
4
- [![Build Status](https://travis-ci.org/technicalpickles/homesick.svg?branch=master)](https://travis-ci.org/technicalpickles/homesick)
5
- [![Dependency Status](https://gemnasium.com/technicalpickles/homesick.svg)](https://gemnasium.com/technicalpickles/homesick)
6
- [![Coverage Status](https://coveralls.io/repos/technicalpickles/homesick/badge.png)](https://coveralls.io/r/technicalpickles/homesick)
7
- [![Code Climate](https://codeclimate.com/github/technicalpickles/homesick.svg)](https://codeclimate.com/github/technicalpickles/homesick)
8
- [![Gitter chat](https://badges.gitter.im/technicalpickles/homesick.svg)](https://gitter.im/technicalpickles/homesick)
4
+ [![CI](https://github.com/technicalpickles/homesick/actions/workflows/ci.yml/badge.svg)](https://github.com/technicalpickles/homesick/actions/workflows/ci.yml)
9
5
 
10
6
  Your home directory is your castle. Don't leave your dotfiles behind.
11
7
 
@@ -164,17 +160,17 @@ and castle
164
160
 
165
161
  Homesick is tested on the following Ruby versions:
166
162
 
167
- * 2.2.6
168
- * 2.3.3
169
- * 2.4.0
163
+ * 3.2
164
+ * 3.3
165
+ * 3.4
170
166
 
171
167
  ## Note on Patches/Pull Requests
172
168
 
173
169
  * Fork the project.
174
170
  * Make your feature addition or bug fix.
175
- * Add tests for it. This is important so I don't break it in a future version unintentionally.
176
- * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
177
- * Send me a pull request. Bonus points for topic branches.
171
+ * Add tests for it. This is important so it doesn't get broken unintentionally in a future version.
172
+ * Commit, but do not touch the rakefile, version, or history. (If you want your own version, that is fine just bump the version in a separate commit that can be ignored when merging.)
173
+ * Open a pull request. Bonus points for topic branches.
178
174
 
179
175
  ## Need homesick without the ruby dependency?
180
176
 
data/Rakefile CHANGED
@@ -1,68 +1,14 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- require_relative 'lib/homesick/version'
4
- begin
5
- Bundler.setup(:default, :development)
6
- rescue Bundler::BundlerError => e
7
- $stderr.puts e.message
8
- $stderr.puts "Run `bundle install` to install missing gems"
9
- exit e.status_code
10
- end
11
- require 'rake'
12
-
13
- require 'jeweler'
14
- Jeweler::Tasks.new do |gem|
15
- gem.name = "homesick"
16
- gem.summary = %Q{Your home directory is your castle. Don't leave your dotfiles behind.}
17
- gem.description = %Q{
18
- Your home directory is your castle. Don't leave your dotfiles behind.
19
-
20
-
21
- Homesick is sorta like rip, but for dotfiles. It uses git to clone a repository containing dotfiles, and saves them in ~/.homesick. It then allows you to symlink all the dotfiles into place with a single command.
22
-
23
- }
24
- gem.email = ["josh@technicalpickles.com", "info@muratayusuke.com"]
25
- gem.homepage = "http://github.com/technicalpickles/homesick"
26
- gem.authors = ["Joshua Nichols", "Yusuke Murata"]
27
- gem.version = Homesick::Version::STRING
28
- gem.license = "MIT"
29
- # Have dependencies? Add them to Gemfile
30
-
31
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
32
- end
33
- Jeweler::GemcutterTasks.new
34
-
1
+ # frozen_string_literal: true
35
2
 
36
3
  require 'rspec/core/rake_task'
37
- RSpec::Core::RakeTask.new(:spec) do |spec|
38
- spec.pattern = FileList['spec/**/*_spec.rb']
39
- end
4
+ require 'rubocop/rake_task'
40
5
 
41
- RSpec::Core::RakeTask.new(:rcov) do |spec|
42
- spec.pattern = 'spec/**/*_spec.rb'
43
- spec.rcov = true
44
- end
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ RuboCop::RakeTask.new
45
8
 
46
- task :rubocop do
47
- if RUBY_VERSION >= '1.9.2'
48
- system('rubocop')
49
- end
50
- end
9
+ task default: %i[spec rubocop]
51
10
 
52
- task :test do
53
- Rake::Task['spec'].execute
54
- Rake::Task['rubocop'].execute
11
+ desc 'Run mutation tests (requires mutant-rspec gem)'
12
+ task :mutant do
13
+ sh 'mutant run'
55
14
  end
56
-
57
- task :default => :test
58
-
59
- require 'rdoc/task'
60
- Rake::RDocTask.new do |rdoc|
61
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
62
-
63
- rdoc.rdoc_dir = 'rdoc'
64
- rdoc.title = "homesick #{version}"
65
- rdoc.rdoc_files.include('README*')
66
- rdoc.rdoc_files.include('lib/**/*.rb')
67
- end
68
-
data/bin/homesick CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pathname'
4
5
  lib = Pathname.new(__FILE__).dirname.join('..', 'lib').expand_path