Skip to content

Instantly share code, notes, and snippets.

@zerowidth
Created May 7, 2012 21:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zerowidth/2630626 to your computer and use it in GitHub Desktop.
Save zerowidth/2630626 to your computer and use it in GitHub Desktop.
A functional, lazily-evaluated solution to https://github.com/KeeperPat/music-yaml-parsing for a "coding challenged" competition
Proc.module_eval { def method_missing(m,*a); call(m.to_s,*a); end }
Array.module_eval { def rest; self[1..-1]; end }
Object.module_eval { def let; yield self; end }
Music = Module.new do
def self.load(filename)
depth = ->(l) { %r(^([\s-]*)\w).match(l)[1].length }
ldepth = ->(l) { %r(^(\s*)\S).match(l)[1].length }
nonzero = ->(n) { n > 0 }
empty = ->(c) { c.empty? }
take_while = ->(p, c) {
c.empty? ? [] : p.(c.first) ? [c.first] + take_while[p, c.rest] : []
}
drop_while = ->(p, c) {
c.empty? ? [] : p.(c.first) ? drop_while[p, c.rest] : c
}
list = ->(*a) {}
kv = ->(ls) { ->(f, ls, k) {
if l = ls.first
ck = ->(l) { %r((\w+):).match(l)[1] }.(l)
d = depth[l]
case ck
when k
v = ->(l) { %r(:\s+(.*)).match(l) }.(l)
case v
when nil then list.(take_while.(->(l){depth[l] > d}, ls.rest))
else v[1]
end
else f.(f, drop_while.(->(l){depth[l] > d}, ls.rest), k)
end
end
}.let { |f| f.curry.(f, ls) } }
list = ->(ls) { ->(f, ls, n) {
if l = ls.first
d = ldepth[l]
v = kv.( [l] + take_while[->(l){ ldepth[l] > d }, ls.rest] )
r = drop_while.(->(l){ldepth[l] > d}, ls.rest)
case n
when "last"
case r
when empty then v
else f.(f, r, n)
end
when 0, "first" then v
when nonzero then f.(f, r, n-1)
else nil
end
end
}.let { |f| f.curry.(f, ls) } }
kv[ File.read(filename).split("\n") ]
end
end
data = Music.load "music.yaml"
require "pp"
puts data["genres"].last["artists"].first["albums"].first["tracks"].last["name"] #=> "But Not For Me"
puts data.genres.last.artists.first.albums.first.tracks.last.name #=> "But Not For Me"
puts data.genres.first.name #=> Classic Rock
puts data.genres[0].artists[0].name #=> Led Zeppelin
puts data.genres[0].artists[0].albums[1].name #=> II
genres:
- name: Classic Rock
artists:
- name: Led Zeppelin
albums:
- name: I
tracks:
- name: Babe, I'm Gonna Leave You
- name: Black Mountain Side
- name: Communication Breakdown
- name: Dazed And Confused
- name: Good Times, Bad Times
- name: How Many More Times
- name: I Can't Quit You Baby
- name: You Shook Me
- name: Your Time Is Gonna Come
- name: II
tracks:
- name: Bring It On Home
- name: Heartbreaker
- name: The Lemon Song
- name: Living Loving Maid
- name: Moby Dick
- name: Ramble On
- name: Thank You
- name: What Is And What Should Never Be
- name: Whole Lotta Love
- name: Jazz
artists:
- name: John Coltrane
albums:
- name: My Favorite Things
tracks:
- name: My Favorite Things
- name: Every Time We Say Goodbye
- name: Summertime
- name: But Not For Me
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment