├── Rakefile ├── lib ├── gaucho │ ├── version.rb │ ├── page.rb │ ├── metadata.rb │ ├── commit.rb │ ├── index.rb │ └── pageset.rb └── gaucho.rb ├── .gitignore ├── Gemfile ├── README.md ├── spec ├── gaucho │ ├── page_spec.rb │ ├── metadata_spec.rb │ ├── index_spec.rb │ ├── commit_spec.rb │ └── pageset_spec.rb ├── generate_fixtures.rb └── fixtures_helper.rb ├── gaucho.gemspec └── .rvmrc /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | Bundler::GemHelper.install_tasks 3 | -------------------------------------------------------------------------------- /lib/gaucho/version.rb: -------------------------------------------------------------------------------- 1 | module Gaucho 2 | VERSION = "0.0.1" 3 | end 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | Gemfile.lock 4 | pkg/* 5 | spec/fixtures/* 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Specify your gem's dependencies in gaucho.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gaucho 2 | 3 | Ruby + Git + Content = Gaucho 4 | 5 | ## Copyright 6 | 7 | Copyright (c) 2011 "Cowboy" Ben Alman 8 | Dual licensed under the MIT and GPL licenses. 9 | 10 | -------------------------------------------------------------------------------- /lib/gaucho.rb: -------------------------------------------------------------------------------- 1 | #require 'forwardable' 2 | 3 | require 'yaml' 4 | 5 | require 'grit' 6 | require 'pp' 7 | 8 | require 'gaucho/pageset' 9 | require 'gaucho/page' 10 | require 'gaucho/commit' 11 | require 'gaucho/metadata' 12 | require 'gaucho/index' 13 | 14 | module Gaucho 15 | # Your code goes here... 16 | end 17 | -------------------------------------------------------------------------------- /lib/gaucho/page.rb: -------------------------------------------------------------------------------- 1 | 2 | module Gaucho 3 | class Page 4 | attr_reader :id, :pageset 5 | 6 | def initialize(id, pageset) 7 | @id = id 8 | @pageset = pageset 9 | end 10 | 11 | # A list of commits for this page. 12 | def commits 13 | return @commits unless @commits.nil? 14 | pc = pageset.page_commits[id] 15 | @commits = pc.collect {|obj| Gaucho::Commit.new obj[:sha], self} 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/gaucho/page_spec.rb: -------------------------------------------------------------------------------- 1 | require 'gaucho' 2 | require 'pp' 3 | 4 | module Gaucho 5 | describe Page do 6 | before do 7 | @pageset = Pageset.new 'spec/fixtures/basic' 8 | @page = Page.new 'page-1', @pageset 9 | end 10 | 11 | describe "#id" do 12 | it "should reflect the passed-in id" do 13 | page = Page.new 'SAMPLE', nil 14 | page.id.should eq 'SAMPLE' 15 | end 16 | end 17 | 18 | describe "#pageset" do 19 | it "should reflect the passed-in pageset" do 20 | @page.pageset.should eq @pageset 21 | end 22 | end 23 | 24 | describe "#commits" do 25 | it "should contain a list of Gaucho::Commit objects" do 26 | @page.commits.all? {|c| c.instance_of? Gaucho::Commit}.should eq true 27 | end 28 | end 29 | end 30 | end -------------------------------------------------------------------------------- /lib/gaucho/metadata.rb: -------------------------------------------------------------------------------- 1 | 2 | # More friendly looking dot-syntax access for hash keys. 3 | # http://mjijackson.com/2010/02/flexible-ruby-config-objects 4 | module Gaucho 5 | class Metadata 6 | def initialize(data = {}) 7 | @data = {} 8 | data.each {|key, value| self[key] = value} 9 | end 10 | 11 | def to_hash 12 | @data 13 | end 14 | 15 | def [](key) 16 | @data[key.downcase.to_sym] 17 | end 18 | 19 | def []=(key, value) 20 | @data[key.downcase.to_sym] = if value.instance_of? Hash 21 | self.class.new value 22 | else 23 | value 24 | end 25 | end 26 | 27 | def method_missing(method, *args) 28 | if method.to_s =~ /^(.+)=$/ 29 | self[$1] = args.first 30 | else 31 | self[method] 32 | end 33 | end 34 | end 35 | end -------------------------------------------------------------------------------- /gaucho.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "gaucho/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "gaucho" 7 | s.version = Gaucho::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ['"Cowboy" Ben Alman'] 10 | s.email = ["TODO: Write your email address"] 11 | s.homepage = "" 12 | s.summary = %q{TODO: Write a gem summary} 13 | s.description = %q{TODO: Write a gem description} 14 | 15 | s.rubyforge_project = "gaucho" 16 | 17 | s.add_dependency "grit", "~> 2.4" 18 | 19 | s.add_development_dependency "rspec", "~> 2.6" 20 | 21 | s.files = `git ls-files`.split("\n") 22 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 23 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 24 | s.require_paths = ["lib"] 25 | end 26 | -------------------------------------------------------------------------------- /lib/gaucho/commit.rb: -------------------------------------------------------------------------------- 1 | 2 | module Gaucho 3 | class Commit 4 | extend Forwardable 5 | 6 | attr_reader :commit, :page 7 | 8 | # Forward Grit::Commit methods to :commit. 9 | def_delegators :commit, :id, :parents, :message, :author, :committer, 10 | :authored_date, :committed_date 11 | 12 | def initialize(commit_id, page) 13 | @page = page 14 | @commit = @page.pageset.repo.commit commit_id 15 | end 16 | 17 | # Grit::Tree for this page at this commit. 18 | def tree 19 | if page.pageset.subdir.nil? 20 | commit.tree/page.id 21 | else 22 | commit.tree/page.pageset.subdir/page.id 23 | end 24 | end 25 | 26 | # Metadata for this commit's page index.md file. 27 | def meta 28 | return @meta unless @meta.nil? 29 | index = tree.blobs.find {|blob| blob.name =~ /^index\./} 30 | @meta = parse_index index.name, index.data 31 | end 32 | 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/gaucho/index.rb: -------------------------------------------------------------------------------- 1 | 2 | module Gaucho 3 | class Index 4 | attr_reader :file_name, :meta 5 | 6 | def initialize(file_name, data) 7 | @file_name = file_name 8 | @data = data 9 | parse_data 10 | end 11 | 12 | private 13 | 14 | # Parse index file into metadata. 15 | def parse_data 16 | docs = [] 17 | YAML.each_document(@data) {|doc| docs << doc}# rescue nil 18 | docs = [{}, @data] unless docs.length == 2 19 | docs.first.each do |key, value| 20 | docs.first[key] = value.collect {|e| e.to_s} if value.instance_of? Array 21 | end 22 | @meta = Gaucho::Metadata.new docs.first 23 | 24 | # meta.excerpt is anything before , meta.content is everything 25 | # before + everything after. 26 | parts = docs.last.split(/^\s*\s*$/im) 27 | @meta.excerpt = (parts[0] || '').chomp 28 | @meta.content = @meta.excerpt + (parts[1] || '').chomp 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /.rvmrc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This is an RVM Project .rvmrc file, used to automatically load the ruby 4 | # development environment upon cd'ing into the directory 5 | 6 | # First we specify our desired [@], the @gemset name is optional. 7 | environment_id="ruby-1.9.2-p180@gaucho" 8 | 9 | # 10 | # First we attempt to load the desired environment directly from the environment 11 | # file. This is very fast and efficicent compared to running through the entire 12 | # CLI and selector. If you want feedback on which environment was used then 13 | # insert the word 'use' after --create as this triggers verbose mode. 14 | # 15 | if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \ 16 | && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] ; then 17 | \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id" 18 | else 19 | # If the environment file has not yet been created, use the RVM CLI to select. 20 | rvm --create "$environment_id" 21 | fi 22 | 23 | # 24 | # If you use an RVM gemset file to install a list of gems (*.gems), you can have 25 | # it be automatically loaded. Uncomment the following and adjust the filename if 26 | # necessary. 27 | # 28 | # filename=".gems" 29 | # if [[ -s "$filename" ]] ; then 30 | # rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d' 31 | # fi 32 | 33 | # 34 | # If you use bundler and would like to run bundle each time you enter the 35 | # directory, you can uncomment the following code. 36 | # 37 | # # Ensure that Bundler is installed. Install it if it is not. 38 | # if ! command -v bundle >/dev/null; then 39 | # printf "The rubygem 'bundler' is not installed. Installing it now.\n" 40 | # gem install bundler 41 | # fi 42 | # 43 | # # Bundle while reducing excess noise. 44 | # printf "Bundling your gems. This may take a few minutes on a fresh clone.\n" 45 | # bundle | grep -v '^Using ' | grep -v ' is complete' | sed '/^$/d' 46 | # 47 | 48 | -------------------------------------------------------------------------------- /spec/gaucho/metadata_spec.rb: -------------------------------------------------------------------------------- 1 | require 'gaucho' 2 | 3 | module Gaucho 4 | describe Metadata do 5 | describe "#to_hash" do 6 | it "should reflect the underlying hash" do 7 | hash = {a: 123} 8 | meta = Gaucho::Metadata.new hash 9 | meta.to_hash.should eq hash 10 | end 11 | end 12 | 13 | describe "#[]" do 14 | it "should access the underlying hash properties" do 15 | hash = {a: 123} 16 | meta = Gaucho::Metadata.new hash 17 | meta[:a].should eq hash[:a] 18 | end 19 | it "should be case insensitive" do 20 | meta = Gaucho::Metadata.new TeSt: 123 21 | meta[:tEsT].should eq 123 22 | end 23 | end 24 | 25 | describe "#[]=" do 26 | it "should set the underlying hash properties" do 27 | meta = Gaucho::Metadata.new 28 | meta[:a] = 123 29 | meta[:a].should eq 123 30 | end 31 | it "should work recursively" do 32 | meta = Gaucho::Metadata.new 33 | meta[:a] = {b: 1} 34 | meta[:a][:b].should eq 1 35 | meta[:a].instance_of?(Gaucho::Metadata).should eq true 36 | end 37 | end 38 | 39 | describe "#[arbitrary property]" do 40 | it "should work" do 41 | meta = Gaucho::Metadata.new a: 123 42 | meta.a.should eq 123 43 | end 44 | it "should work recursively" do 45 | meta = Gaucho::Metadata.new a: {b: 1} 46 | meta.a.b.should eq 1 47 | end 48 | it "should be case insensitive" do 49 | meta = Gaucho::Metadata.new TeSt: 123 50 | meta.tEsT.should eq 123 51 | end 52 | it "should allow setting" do 53 | meta = Gaucho::Metadata.new 54 | meta.a = 123 55 | meta.a.should eq 123 56 | end 57 | it "should allow setting recursively" do 58 | meta = Gaucho::Metadata.new 59 | meta.a = {b: 1} 60 | meta.a.b.should eq 1 61 | end 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /spec/gaucho/index_spec.rb: -------------------------------------------------------------------------------- 1 | require 'gaucho' 2 | 3 | module Gaucho 4 | describe Index do 5 | describe "#file_name" do 6 | it "should reflect the passed-in file_name" do 7 | index = Gaucho::Index.new 'index.md', 'SAMPLE' 8 | index.file_name.should eq 'index.md' 9 | end 10 | end 11 | 12 | describe "#meta" do 13 | before do 14 | @excerpt = "This is an excerpt\nspread over two lines." 15 | @more = "And this is the rest\nof the content." 16 | @data_simple = @excerpt 17 | @data_more = "#{@excerpt}\n\n#{@more}" 18 | @data_yaml = <<-EOF.gsub(/^\s+/, '') 19 | Str1: A test string 20 | Str2: "Another test string" 21 | Array1: [foo, bar, baz] 22 | Array2: [1, 2, 3] 23 | --- | 24 | #{@data_more} 25 | EOF 26 | end 27 | it "should parse simple text data" do 28 | index = Gaucho::Index.new 'index.md', @data_simple 29 | index.meta.excerpt.should eq @excerpt 30 | index.meta.content.should eq @excerpt 31 | end 32 | it "should parse simple text data" do 33 | index = Gaucho::Index.new 'index.md', @data_more 34 | index.meta.excerpt.should eq @excerpt 35 | index.meta.content.should eq "#{@excerpt}\n#{@more}" 36 | end 37 | it "should parse yaml metadata + content" do 38 | index = Gaucho::Index.new 'index.md', @data_yaml 39 | index.meta.str1.should eq "A test string" 40 | index.meta.str2.should eq "Another test string" 41 | index.meta.array1.should eq %w{foo bar baz} 42 | index.meta.array2.should eq %w{1 2 3} 43 | index.meta.excerpt.should eq @excerpt 44 | index.meta.content.should eq "#{@excerpt}\n#{@more}" 45 | end 46 | it "should not care about --- before metadata" do 47 | index1 = Gaucho::Index.new 'index.md', @data_yaml 48 | index2 = Gaucho::Index.new 'index.md', "---\n#{@data_yaml}" 49 | index1.meta.to_hash.should eq index2.meta.to_hash 50 | end 51 | end 52 | end 53 | end -------------------------------------------------------------------------------- /spec/generate_fixtures.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require './fixtures_helper' 4 | 5 | # Pageset.new 'test' do |r| 6 | # r.write 'foo/bar.txt' => 'this is some sample content for foo' 7 | # r.write 'baz.txt' => 'this is some sample content for bar' 8 | # r.git_add_commit 'commit 1' 9 | # 10 | # r.append 'baz.txt' => 'bar has been modified!!!' 11 | # r.git_add_commit 'commit 2' 12 | # end 13 | # 14 | # Pageset.new 'two-pages' do |r| 15 | # r.page 'page-one' do |p| 16 | # p.meta 'Title' => 'Page One!', 'Tags' => %w{foo bar} 17 | # p.content 'this is sample page one' 18 | # r.git_add_commit 'page 1, commit 1' 19 | # 20 | # p.meta 'Title' => 'Page One Modified!', 'Tags' => %w{foo bar baz} 21 | # r.git_add_commit 'page 1, commit 2' 22 | # end 23 | # 24 | # r.page 'page-two' do |p| 25 | # p.meta 'Title' => 'Page Two!', 'Tags' => %w{bar baz} 26 | # p.content 'this is sample page two' 27 | # r.git_add_commit 'page 2, commit 1' 28 | # 29 | # p.content 'this is sample page two, modified!' 30 | # p.write 'foo.txt' => 'content for foo.txt' 31 | # r.git_add_commit 'page 2, commit 2' 32 | # 33 | # p.append 'foo.txt' => 'more content for foo.txt!' 34 | # r.git_add_commit 'page 2, commit 3' 35 | # end 36 | # end 37 | 38 | Pageset.new 'basic' do |r| 39 | 1.upto(3).each do |i| 40 | r.page "page-#{i}" do |p| 41 | p.meta 'Title' => "Page #{i}", 'Tags' => %w{foo bar baz} 42 | p.content "Sample content for page #{i}." 43 | r.git_add_commit "Created page #{i}." 44 | p.content "Modified content for page #{i}." 45 | p.write "file#{i}.txt" => "Sample file#{i} content" 46 | r.git_add_commit "Updated page #{i}." 47 | end 48 | end 49 | end 50 | 51 | Pageset.new 'subdir' do |r| 52 | %w{foo bar}.each do |subdir| 53 | 1.upto(2).each do |i| 54 | r.page "#{subdir}/#{subdir}-page-#{i}" do |p| 55 | p.meta 'Title' => "Page #{i}", 'Tags' => %w{foo bar baz} 56 | p.content "Sample content for #{subdir} page #{i}." 57 | r.git_add_commit "Created #{subdir} page #{i}." 58 | p.content "Modified content for #{subdir} page #{i}." 59 | p.write "file#{i}.txt" => "Sample file#{i} content" 60 | r.git_add_commit "Updated #{subdir} page #{i}." 61 | end 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/gaucho/pageset.rb: -------------------------------------------------------------------------------- 1 | 2 | module Gaucho 3 | class Pageset 4 | include Enumerable 5 | 6 | attr_reader :repo, :subdir 7 | 8 | def initialize(repo, options = {}) 9 | # Init repo 10 | @repo = repo 11 | @repo = Grit::Repo.new(@repo) unless repo.instance_of? Grit::Repo 12 | 13 | # Initialize from options, overriding these defaults. 14 | { subdir: nil 15 | }.merge(options).each do |key, value| 16 | instance_variable_set "@#{key}".to_sym, value 17 | end 18 | 19 | # Ensure a specified subdir has a trailing slash. 20 | @subdir += '/' unless subdir.nil? || @subdir =~ %r{/$} 21 | end 22 | 23 | # Allow enumeration. 24 | def each 25 | if block_given? then 26 | pages.each {|page| yield page} 27 | else 28 | to_enum 29 | end 30 | end 31 | 32 | # Get a specific page by its id. 33 | def [](id) 34 | pages 35 | @pages_by_id[id] 36 | end 37 | 38 | # Get all pages. 39 | def pages 40 | return @pages unless @pages.nil? 41 | 42 | # Build pages. 43 | @pages = [] 44 | @pages_by_id = {} 45 | page_commits.each do |id, commits| 46 | page = Gaucho::Page.new id, self 47 | @pages << page 48 | @pages_by_id[id] = page 49 | end 50 | @pages 51 | end 52 | 53 | # Get commit index for this repo. The git log is parsed manually, because 54 | # the structure Gaucho needs doesn't seem to exist anywhere in Grit. 55 | def page_commits 56 | return @page_commits unless @page_commits.nil? 57 | 58 | # Build page commit index. 59 | @page_commits = Hash.new {|h, k| h[k] = []} 60 | 61 | log = @repo.git.native(:log, {pretty: 'oneline', name_only: true, 62 | reverse: true, timeout: false}) 63 | 64 | sha = nil 65 | log.split("\n").each do |line| 66 | if line =~ /^([0-9a-f]{40})/ 67 | # Line is SHA, save for later. 68 | sha = $1 69 | elsif line =~ %r{^#{@subdir}(.*?)/(.*)} 70 | # Line is file path, push last seen SHA + file path onto this page's 71 | # array. 72 | pc = @page_commits[$1] 73 | # Create new object for this SHA, if necessary. 74 | pc << {sha: sha, files: []} if pc.empty? || sha != pc.last[:sha] 75 | # Push file onto this SHA's files array. 76 | pc.last[:files] << $2 77 | end 78 | end 79 | @page_commits 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /spec/gaucho/commit_spec.rb: -------------------------------------------------------------------------------- 1 | require 'gaucho' 2 | require 'pp' 3 | 4 | module Gaucho 5 | describe Commit do 6 | before do 7 | @pageset = Pageset.new 'spec/fixtures/basic' 8 | @page = Page.new 'page-1', @pageset 9 | 10 | # Easiest way to get a valid commit SHA for this pageset. 11 | @id = @page.commits.last.id 12 | @commit = Gaucho::Commit.new @id, @page 13 | end 14 | 15 | describe "#id" do 16 | it "should reflect the passed-in id" do 17 | commit = Gaucho::Commit.new @id, @page 18 | commit.id.should eq @id 19 | end 20 | end 21 | 22 | describe "#commit" do 23 | it "should be a Grit::Commit object" do 24 | @commit.commit.instance_of?(Grit::Commit).should eq true 25 | end 26 | 27 | it "should be the correct Grit::Commit object" do 28 | @commit.commit.to_hash.should eq({ 29 | "id"=>"56dfc6a4205432dfaba127fcbe1ae146c49d3748", 30 | "parents"=>[{"id"=>"a018c1844455aa6ee9d8b48fc6826e7d70963d74"}], 31 | "tree"=>"b15fe84ffee91f70cd2616cdacb4da9a9bae08ce", 32 | "message"=>"Updated page 1.", 33 | "author"=>{"name"=>"Ben Alman", "email"=>"cowboy@rj3.net"}, 34 | "committer"=>{"name"=>"Ben Alman", "email"=>"cowboy@rj3.net"}, 35 | "authored_date"=>"2000-01-03T09:00:00-08:00", 36 | "committed_date"=>"2000-01-04T09:00:00-08:00" 37 | }) 38 | end 39 | end 40 | 41 | %w{id parents message author committer authored_date committed_date}.each do |method| 42 | describe "##{method}" do 43 | it "should foward to the underlying Grit::Commit object" do 44 | @commit.public_send(method.to_sym).should eq @commit.commit.public_send(method.to_sym) 45 | end 46 | end 47 | end 48 | 49 | describe "#tree" do 50 | it "should reflect the page's tree for this commit" do 51 | @commit.tree.contents.map(&:basename).should eq %w{file1.txt index.md} 52 | end 53 | it "should reflect the page's tree for this commit (w/subdir)" do 54 | pageset = Pageset.new 'spec/fixtures/subdir', subdir: 'foo' 55 | page = Page.new 'foo-page-1', pageset 56 | id = page.commits.last.id 57 | commit = Gaucho::Commit.new id, page 58 | commit.tree.contents.map(&:basename).should eq %w{file1.txt index.md} 59 | end 60 | end 61 | 62 | describe "#meta" do 63 | it "should reflect the commit's page metadata" do 64 | #pp @commit.meta 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /spec/gaucho/pageset_spec.rb: -------------------------------------------------------------------------------- 1 | require 'gaucho' 2 | require 'pp' 3 | 4 | module Gaucho 5 | describe Pageset do 6 | before do 7 | @pageset = Pageset.new 'spec/fixtures/basic' 8 | end 9 | 10 | describe "#repo" do 11 | it "should be a Grit::Repo (passing in a path)" do 12 | @pageset.repo.instance_of?(Grit::Repo).should eq true 13 | end 14 | it "should be a Grit::Repo (passing in a repo)" do 15 | repo = Grit::Repo.new 'spec/fixtures/basic' 16 | pageset = Pageset.new repo 17 | pageset.repo.instance_of?(Grit::Repo).should eq true 18 | end 19 | end 20 | 21 | describe "#subdir" do 22 | it "should be nil by default" do 23 | pageset = Pageset.new 'spec/fixtures/subdir' 24 | pageset.subdir.should eq nil 25 | end 26 | it "should reflect the passed-in subdir option" do 27 | pageset = Pageset.new 'spec/fixtures/subdir', subdir: 'foo/' 28 | pageset.subdir.should eq 'foo/' 29 | end 30 | it "should always have a trailing /" do 31 | pageset = Pageset.new 'spec/fixtures/subdir', subdir: 'foo' 32 | pageset.subdir.should eq 'foo/' 33 | end 34 | end 35 | 36 | # describe "#path" do 37 | # it "should be the path of the repo + the subdir" do 38 | # path = 'spec/fixtures/subdir' 39 | # subdir = 'foo' 40 | # dir = File.expand_path "#{path}/#{subdir}" 41 | # pageset = Pageset.new path, subdir: subdir 42 | # pageset.path.should eq dir 43 | # end 44 | # end 45 | 46 | describe "#page_commits" do 47 | # note: this is overly implementation-specific 48 | def make_test(page_id_regex) 49 | Proc.new do |id, commits| 50 | id =~ page_id_regex && 51 | commits.count == 2 && 52 | commits.first[:files].count == 1 && 53 | commits.last[:files].count == 2 54 | end 55 | end 56 | it "should parse the commit log properly" do 57 | @pageset.page_commits.all?(&make_test(/^page-\d$/)).should eq true 58 | end 59 | it "should parse the commit log properly when subdir is used" do 60 | %w{foo bar}.each do |subdir| 61 | pageset = Pageset.new 'spec/fixtures/subdir', subdir: subdir 62 | pageset.page_commits.all?(&make_test(/^#{subdir}-page-\d$/)).should eq true 63 | end 64 | end 65 | end 66 | 67 | describe "#[]" do 68 | it "should allow access to pages by their id" do 69 | @pageset['page-1'].instance_of?(Gaucho::Page).should eq true 70 | @pageset['nonexistent'].should eq nil 71 | end 72 | end 73 | 74 | describe "#pages" do 75 | it "should allow access to all pages" do 76 | @pageset.pages.count.should eq 3 77 | @pageset.pages.all? {|page| page.instance_of? Gaucho::Page}.should eq true 78 | end 79 | end 80 | 81 | it "should behave like an Enumerable" do 82 | # Enumeration w/ block 83 | @pageset.inject(0) {|sum, page| sum += 1}.should eq 3 84 | # Enumerator w/o block 85 | @pageset.each.inject(0) {|sum, page| sum += 1}.should eq 3 86 | # Etc 87 | @pageset.count.should eq 3 88 | @pageset.first.instance_of?(Gaucho::Page).should eq true 89 | @pageset.all? {|page| page.instance_of? Gaucho::Page}.should eq true 90 | end 91 | 92 | #it "should default to sorting by commit date" 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /spec/fixtures_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'pp' 4 | require 'fileutils' 5 | require 'yaml' 6 | 7 | class Repo 8 | # create a new repo 9 | def initialize(repo_path) 10 | @time = Time.new(1999, 12, 31, 12, 0, 0, '-05:00') 11 | @repo_path = File.join 'fixtures', repo_path 12 | @pwd = FileUtils.pwd 13 | FileUtils.rm_rf @repo_path 14 | FileUtils.mkdir_p @repo_path 15 | FileUtils.cd @repo_path 16 | `git init .` 17 | yield self if block_given? 18 | done 19 | end 20 | 21 | # cleanup 22 | def done 23 | FileUtils.cd @pwd 24 | end 25 | 26 | # write some files 27 | def write(files = {}, mode = 'w') 28 | files.each do |path, content| 29 | FileUtils.mkdir_p(File.dirname path) 30 | File.open(path, mode) {|f| f.write content} 31 | end 32 | end 33 | 34 | # append to some files 35 | def append(files) 36 | write files, 'a' 37 | end 38 | 39 | # git add some files 40 | def git_add(files = ['.']) 41 | files.each {|file| `git add #{file}`} 42 | end 43 | 44 | # git commit with message 45 | def git_commit(message = 'bloops') 46 | # fake author / commit dates 47 | @time += 86400 48 | author_time = "#{@time.to_i} -0500" 49 | @time += 86400 50 | commit_time = "#{@time.to_i} -0500" 51 | `export GIT_AUTHOR_DATE="#{author_time}"; export GIT_COMMITTER_DATE="#{commit_time}"; git commit -m "#{message}"` 52 | end 53 | 54 | # git add + commit 55 | def git_add_commit(message = nil) 56 | git_add 57 | git_commit message 58 | end 59 | end 60 | 61 | class Pageset < Repo 62 | def page(page_name, &block) 63 | Page.new self, page_name, &block 64 | end 65 | end 66 | 67 | class Page 68 | def initialize(pageset, page_name) 69 | @pageset = pageset 70 | @page_name = page_name 71 | yield self if block_given? 72 | end 73 | 74 | # page index file 75 | def index_path 76 | File.join(@page_name, 'index.md') 77 | end 78 | 79 | # get/set metadata 80 | def meta(meta = nil) 81 | docs = read_index 82 | if !meta.nil? 83 | docs[0].merge! meta 84 | write_index docs 85 | end 86 | docs[0] 87 | end 88 | 89 | # get/set content 90 | def content(content = nil) 91 | docs = read_index 92 | if !content.nil? 93 | docs[1] = content 94 | write_index docs 95 | end 96 | docs[1] 97 | end 98 | 99 | # set content by appending 100 | def content_append(c = '') 101 | content(content + c) 102 | end 103 | 104 | # get all yaml docs from this page's index.md file 105 | def read_index 106 | docs = [] 107 | if File.exists? index_path 108 | File.open(index_path) {|file| YAML.each_document(file) {|doc| docs << doc}} 109 | end 110 | docs[0] = {} if docs[0].nil? 111 | docs[1] = '' if docs[1].nil? 112 | docs 113 | end 114 | 115 | # write all yaml docs to this page's index.md file 116 | def write_index(docs) 117 | # Since this script tries to simulate how user data will actually be stored, 118 | # ie. without extra quoting or \\u-style escaping, and because .to_yaml escapes 119 | # unicode and quotes multi-line strings, YAML serialization is done manually. 120 | metas = [] 121 | docs[0].each do |key, value| 122 | metas << if value.instance_of? Array 123 | "#{key}: [#{value.join(', ')}]" 124 | else 125 | "#{key}: #{value}" 126 | end 127 | end 128 | meta = if metas.empty? 129 | '---' 130 | else 131 | metas.join("\n") 132 | end 133 | @pageset.write index_path => "#{meta}\n--- |\n#{docs[1]}\n" 134 | end 135 | 136 | # write some files 137 | def write(files = {}, mode = 'w') 138 | f = {} 139 | files.each {|path, content| f[File.join @page_name, path] = content} 140 | @pageset.write f, mode 141 | end 142 | 143 | # append to some files 144 | def append(files) 145 | write files, 'a' 146 | end 147 | end 148 | --------------------------------------------------------------------------------