Module: Ruby2D::CLI::Examples

Defined in:
lib/ruby2d/cli/examples.rb

Constant Summary collapse

EXAMPLES_DIR =
File.expand_path('../../../examples', __dir__)
ROOT_DIR =

The gem root, where the bundled assets/ directory sits alongside examples/. Examples resolve asset paths relative to this — the same relative layout ruby2d build mounts into the web VFS and copies into the native bundle — so example runs chdir here (see run).

File.expand_path('..', EXAMPLES_DIR)

Class Method Summary collapse

Class Method Details

.allObject



63
64
65
# File 'lib/ruby2d/cli/examples.rb', line 63

def self.all
  @all ||= Dir.glob("#{EXAMPLES_DIR}/*.rb").sort.map { |p| parse(p) }
end

.browseObject



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/ruby2d/cli/examples.rb', line 103

def self.browse
  list = all
  if list.empty?
    puts "\n  No examples found.\n\n"
    return
  end

  Browser.run(list: list, label: 'Examples', footer_action: 'run',
              fallback: -> { print_list }) do |ex|
    puts
    puts "  #{'Ruby 2D'.ruby2d_red.bold} — Examples"
    puts
    puts "  Running #{ex[:title].bold} #{"(#{ex[:name]}.rb)".dim}"
    puts
    print_header(ex)
    ok = run(ex)
    unless ok
      print "\n  #{'Example exited with errors. Press Enter to continue…'.dim}"
      $stdin.gets
    end
  end
end

.find(query) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ruby2d/cli/examples.rb', line 67

def self.find(query)
  list = all
  if query.match?(/\A\d+\z/)
    idx = query.to_i
    # 1-based; out-of-range (incl. 0) returns nil rather than wrapping.
    return idx.between?(1, list.length) ? list[idx - 1] : nil
  end
  norm = ->(s) { s.downcase.tr('-_', ' ').delete("'").squeeze(' ').strip }
  q = norm.call(query)
  return nil if q.empty?  # an empty query must not match (and run) the first item

  list.find { |e| norm.call(e[:name]) == q || norm.call(e[:title]) == q } ||
    list.find { |e| norm.call(e[:name]).include?(q) || norm.call(e[:title]).include?(q) }
end

.parse(path) ⇒ Object

Parse the leading comment block from an example file. The convention across examples/*.rb is:

# Title
# Short description (one or two lines, shown in the picker preview).
#
# Longer narrative — controls, context, anything beyond the tagline.

The short description (first paragraph after the title) becomes :description; the entire post-title block becomes :header.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/ruby2d/cli/examples.rb', line 26

def self.parse(path)
  title = nil
  header = []
  File.foreach(path) do |line|
    line = line.chomp
    break unless line.start_with?('#')
    stripped = line.sub(/^#\s?/, '')
    if title.nil?
      title = stripped unless stripped.empty?
      next
    end
    header << stripped
  end
  # Drop leading/trailing blank separator lines around the header block.
  header.shift while header.first == ''
  header.pop   while header.last  == ''
  # `description` is the first paragraph of the header, joined as one line.
  first_para = header.take_while { |l| !l.empty? }
  name = File.basename(path, '.rb')
  {
    name: name,
    title: title || name,
    description: first_para.join(' ').strip,
    header: header,
    path: path
  }
end

Print the example's leading comment block (prose only, no title) in dim text, indented to match the surrounding "Running …" message.



56
57
58
59
60
61
# File 'lib/ruby2d/cli/examples.rb', line 56

def self.print_header(example)
  lines = example[:header]
  return if lines.nil? || lines.all?(&:empty?)
  lines.each { |line| puts(line.empty? ? '' : "  #{line.dim}") }
  puts
end

Non-interactive list, matching the style of ruby2d usage.



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/ruby2d/cli/examples.rb', line 89

def self.print_list
  list = all
  if list.empty?
    puts "\n  No examples found.\n\n"
    return
  end
  w = list.length.to_s.length
  puts "\n  #{'Ruby 2D'.ruby2d_red.bold} — Examples\n\n"
  list.each_with_index do |ex, i|
    puts "  #{(i + 1).to_s.rjust(w).dim}  #{ex[:title]}"
  end
  puts "\n  #{'ruby2d examples <name|number>'.dim}\n\n"
end

.run(example) ⇒ Object



82
83
84
85
86
# File 'lib/ruby2d/cli/examples.rb', line 82

def self.run(example)
  # Run from `ROOT_DIR` so an example's relative asset paths (e.g.
  # `assets/resources/spritesheets`) resolve against the bundled assets.
  system(Gem.ruby, example[:path], chdir: ROOT_DIR)
end