├── .gitignore ├── Gemfile ├── lib ├── uke │ ├── version.rb │ ├── fretboard.rb │ └── chords.rb └── uke.rb ├── CHANGELOG.md ├── bin └── uke-chords ├── Rakefile ├── uke.gemspec ├── MIT-LICENSE.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | /pkg 3 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | gem 'minitest' 6 | -------------------------------------------------------------------------------- /lib/uke/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Uke 4 | VERSION = "1.0.3" 5 | end 6 | 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## CHANGELOG 2 | 3 | ### 1.0.3 4 | 5 | - Relax Ruby version requirement to allow Ruby 3.0 6 | 7 | ### 1.0.2 8 | 9 | - Add more chords 10 | - Improve "fingering" output style 11 | 12 | ### 1.0.1 13 | 14 | - Support "fingering" output style, by @paulgoetze 15 | 16 | ### 1.0.0 17 | 18 | - Initial release 19 | 20 | -------------------------------------------------------------------------------- /bin/uke-chords: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | #require 'uke' 4 | require_relative '../lib/uke' 5 | require 'rationalist' 6 | 7 | args = Rationalist.parse( 8 | boolean: [:help, :version], 9 | string: [:style], 10 | default: { style: :small }, 11 | alias: { s: :style, v: :version } 12 | ) 13 | 14 | case 15 | when args[:v] 16 | $stderr.puts Uke::VERSION 17 | when args[:help] 18 | puts < 2.0' 22 | gem.add_dependency 'artii', '~> 2.1' 23 | end 24 | -------------------------------------------------------------------------------- /lib/uke.rb: -------------------------------------------------------------------------------- 1 | require 'artii' 2 | 3 | require_relative "uke/version" 4 | require_relative "uke/chords" 5 | require_relative "uke/fretboard" 6 | 7 | class Uke 8 | def print_chord_list 9 | puts Uke::CHORDS.keys.join " " 10 | end 11 | 12 | def print_chords(which, style = nil) 13 | Array(which).each{ |chord_name| 14 | chords = CHORDS[chord_name] 15 | if !chords.empty? 16 | puts chords.reduce( 17 | chord_name_to_ascii_lines(chord_name) 18 | ){ |old_lines, chord| 19 | old_lines.zip(Fretboard.new(chord, style).lines).map(&:join) 20 | }.join($/) 21 | else 22 | $stderr.puts "\n #{chord_name} not found" 23 | end 24 | } 25 | end 26 | 27 | private 28 | 29 | def chord_name_to_ascii_lines(chord) 30 | a = Artii::Base.new# font: 'roman' 31 | res = [" ", " ", " "] 32 | res += a.asciify(chord).split($/) 33 | res += [" "] 34 | 35 | max = res.max_by(&:size).size 36 | 37 | res.map{ |l| " " + l.ljust(max) } 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Jan Lelis, https://janlelis.com 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /lib/uke/fretboard.rb: -------------------------------------------------------------------------------- 1 | class Uke 2 | class Fretboard 3 | STYLES = { 4 | small: { open: " ∘", finger: " •" }, 5 | medium: { open: " ⚪", finger: " ⚫"}, 6 | large: { open: " ◯", finger: " " }, 7 | fingering: {open: " ◯", finger: [" ➊", " ➋", " ➌", " ➍"]} 8 | } 9 | 10 | def initialize(chord, style = nil) 11 | @chord = chord 12 | @style = style.to_sym 13 | raise ArgumentError, 'Unknown style' unless STYLES[@style] 14 | @config = chord_to_config(@chord) 15 | end 16 | 17 | def lines 18 | (TEMPLATE % @config).split($/).map do |line| 19 | matches = line.match(/(([➊➋➌➍]\s{2,})+[^│])/) 20 | 21 | if matches 22 | part = matches.captures.first 23 | line.gsub(part, part.gsub(/\s{2}/, ' ')) 24 | else 25 | line 26 | end 27 | end 28 | end 29 | 30 | private 31 | 32 | def chord_to_config(chord) 33 | config = DEFAULT_CONFIG.dup 34 | 35 | chord.positions.each_with_index do |position, index| 36 | if position == 0 37 | config[index] = STYLES[@style][:open] 38 | else 39 | finger = finger_symbol(chord, index) 40 | finger = index === 3 && @style != :small ? finger.strip : finger 41 | config[position * 4 + index] = finger 42 | end 43 | end 44 | 45 | config 46 | end 47 | 48 | def finger_symbol(chord, index) 49 | finger = STYLES[@style][:finger] 50 | 51 | if @style == :fingering 52 | return STYLES[:large][:finger] unless chord.fingers 53 | 54 | finger_index = chord.fingers[index] - 1 55 | finger_index.negative? ? STYLES[:large][:finger] : finger[finger_index] 56 | else 57 | STYLES[@style][:finger] 58 | end 59 | end 60 | 61 | DEFAULT_CONFIG = [ 62 | " ", " ", " ", " ", 63 | " │", " │", " │", " │", 64 | " │", " │", " │", " │", 65 | " │", " │", " │", " │", 66 | " │", " │", " │", " │", 67 | " │", " │", " │", " │", 68 | ] 69 | 70 | TEMPLATE = <