makura 2009.05.27
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.
- data/CHANGELOG +340 -0
- data/COPYING +18 -0
- data/MANIFEST +42 -0
- data/README.md +41 -0
- data/Rakefile +32 -0
- data/bin/makura +12 -0
- data/example/blog.rb +50 -0
- data/example/couch/map/author_all.js +5 -0
- data/example/couch/map/author_posts.js +5 -0
- data/example/couch/map/post_all.js +5 -0
- data/example/couch/map/post_comments.js +5 -0
- data/example/couch/reduce/sum_length.js +7 -0
- data/lib/makura.rb +66 -0
- data/lib/makura/database.rb +216 -0
- data/lib/makura/design.rb +37 -0
- data/lib/makura/error.rb +14 -0
- data/lib/makura/http_methods.rb +19 -0
- data/lib/makura/layout.rb +64 -0
- data/lib/makura/model.rb +370 -0
- data/lib/makura/plugin/localize.rb +68 -0
- data/lib/makura/plugin/pager.rb +56 -0
- data/lib/makura/server.rb +203 -0
- data/lib/makura/uuid_cache.rb +23 -0
- data/lib/makura/version.rb +3 -0
- data/makura.gemspec +31 -0
- data/tasks/authors.rake +30 -0
- data/tasks/bacon.rake +66 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/copyright.rake +21 -0
- data/tasks/gem.rake +22 -0
- data/tasks/gem_installer.rake +76 -0
- data/tasks/git.rake +46 -0
- data/tasks/grancher.rake +12 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/metric_changes.rake +32 -0
- data/tasks/rcov.rake +23 -0
- data/tasks/release.rake +69 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/todo.rake +27 -0
- data/tasks/traits.rake +21 -0
- data/tasks/yard.rake +4 -0
- data/tasks/ycov.rake +22 -0
- metadata +105 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Makura
|
|
2
|
+
module Plugin
|
|
3
|
+
module Pager
|
|
4
|
+
module SingletonMethods
|
|
5
|
+
def pager(page, limit)
|
|
6
|
+
Makura::Plugin::Pager::Pagination.new(self, :pager, page, limit)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Pagination
|
|
11
|
+
def initialize(model, view, page, limit)
|
|
12
|
+
@model, @view, @page, @limit = model, view, page, limit
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# /pager/_all_docs?count=10&group=true
|
|
16
|
+
# /pager/_all_docs?startkey=%224f9dca1c66121f9320a69553546db07a%22&startkey_docid=4f9dca1c66121f9320a69553546db07a&skip=1&descending=false&count=10&group=true
|
|
17
|
+
# /pager/_all_docs?startkey=%22_design%2FUser%22&startkey_docid=_design%2FUser&skip=1&descending=false&count=10&group=true
|
|
18
|
+
# /pager/_all_docs?startkey=%22d850f0801686b85035680bb6f38d5c5c%22&startkey_docid=d850f0801686b85035680bb6f38d5c5c&skip=1&descending=false&count=10&group=true
|
|
19
|
+
|
|
20
|
+
# NOTE:
|
|
21
|
+
# * descending should be true if you page backwards
|
|
22
|
+
|
|
23
|
+
include Enumerable
|
|
24
|
+
|
|
25
|
+
def each(start_id = nil, descending = false, &block)
|
|
26
|
+
opts = {
|
|
27
|
+
:count => @limit,
|
|
28
|
+
:group => true,
|
|
29
|
+
:descending => descending,
|
|
30
|
+
# :include_docs => true,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if start_id
|
|
34
|
+
opts[:skip] = 1
|
|
35
|
+
opts[:startkey_docid] = start_id
|
|
36
|
+
opts[:startkey] = start_id
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@model.view(@view, opts).each(&block)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def count
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def first_page?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def last_page?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def empty?
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
module Makura
|
|
2
|
+
class Server
|
|
3
|
+
include HTTPMethods
|
|
4
|
+
attr_accessor :uri, :cache_ttl, :cache_tries
|
|
5
|
+
|
|
6
|
+
COUCHDB_URI = 'http://localhost:5984'
|
|
7
|
+
CACHE_TTL = 5
|
|
8
|
+
CACHE_TRIES = 2
|
|
9
|
+
|
|
10
|
+
# Usage:
|
|
11
|
+
# server = Makura::Server.new
|
|
12
|
+
# #<URI::HTTP:0xb778ce38 URL:http://localhost:5984>
|
|
13
|
+
# server.info
|
|
14
|
+
# {"couchdb"=>"Welcome", "version"=>"0.9.0a718650-incubating"}
|
|
15
|
+
|
|
16
|
+
def initialize(uri = COUCHDB_URI, cache_ttl = CACHE_TTL, cache_tries = CACHE_TRIES)
|
|
17
|
+
@uri = URI(uri.to_s)
|
|
18
|
+
@cache_ttl = cache_ttl
|
|
19
|
+
@cache_tries = cache_tries
|
|
20
|
+
@uuids = UUIDCache.new(self)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def inspect
|
|
24
|
+
@uri.inspect
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# General queries
|
|
28
|
+
|
|
29
|
+
# Answers with general couchdb info, looks like:
|
|
30
|
+
#
|
|
31
|
+
# Usage:
|
|
32
|
+
# server.info
|
|
33
|
+
# # {'couchdb' => 'Welcome', 'version' => '0.9.0a718650-incubating'}
|
|
34
|
+
def info
|
|
35
|
+
get('/')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Answers with configuration info.
|
|
39
|
+
#
|
|
40
|
+
# Usage:
|
|
41
|
+
# server.config
|
|
42
|
+
#
|
|
43
|
+
def config
|
|
44
|
+
get('/_config')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Issue restart of the CouchDB daemon.
|
|
48
|
+
#
|
|
49
|
+
# Usage:
|
|
50
|
+
# server.restart
|
|
51
|
+
# # {'ok' => true}
|
|
52
|
+
def restart
|
|
53
|
+
post('/_restart')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Array of names of databases on the server
|
|
57
|
+
#
|
|
58
|
+
# Usage:
|
|
59
|
+
# server.databases
|
|
60
|
+
# # ["another", "blog", "makura-spec"]
|
|
61
|
+
def databases
|
|
62
|
+
get('/_all_dbs')
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Return new database instance using this server instance.
|
|
66
|
+
#
|
|
67
|
+
# Usage:
|
|
68
|
+
# foo = server.database('foo')
|
|
69
|
+
# # #<Makura::Database 'http://localhost:5984/foo'>
|
|
70
|
+
# server.databases
|
|
71
|
+
# # ["another", "blog", "foo", "makura-spec"]
|
|
72
|
+
|
|
73
|
+
def database(name)
|
|
74
|
+
Database.new(self, name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Answers with an uuid from the UUIDCache.
|
|
78
|
+
#
|
|
79
|
+
# Usage:
|
|
80
|
+
# server.next_uuid
|
|
81
|
+
# # "55fdca746fa5a5b56f5270875477a2cc"
|
|
82
|
+
|
|
83
|
+
def next_uuid
|
|
84
|
+
@uuids.next
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def start_cache(namespace = 'makura', *servers)
|
|
88
|
+
servers << 'localhost:11211' if servers.empty?
|
|
89
|
+
@cache = MemCache.new(servers, :namespace => namespace, :multithread => true)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def stop_cache
|
|
93
|
+
@cache = nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def cached(request, ttl = cache_ttl, tries = cache_tries)
|
|
97
|
+
key = request[:url]
|
|
98
|
+
|
|
99
|
+
unless response = @cache.get(key)
|
|
100
|
+
response = execute(request)
|
|
101
|
+
@cache.add(key, response, ttl)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
return response
|
|
105
|
+
rescue MemCache::MemCacheError => error
|
|
106
|
+
servers = @cache.servers.map{|s| "#{s.host}:#{s.port}"}
|
|
107
|
+
start_cache(@cache.namespace, *servers)
|
|
108
|
+
tries -= 1
|
|
109
|
+
retry if tries > 0
|
|
110
|
+
warn "[makura caching disabled] #{error.message}"
|
|
111
|
+
@cache = nil
|
|
112
|
+
execute(request)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Helpers
|
|
116
|
+
|
|
117
|
+
def request(method, path, params = {})
|
|
118
|
+
keep_raw = params.delete(:raw)
|
|
119
|
+
payload = params.delete(:payload)
|
|
120
|
+
payload = payload.to_json if payload and not keep_raw
|
|
121
|
+
headers = {}
|
|
122
|
+
|
|
123
|
+
if content_type = params.delete('Content-Type')
|
|
124
|
+
headers['Content-Type'] = content_type
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
params.delete_if{|k,v| v.nil? }
|
|
128
|
+
uri = uri(path, params).to_s
|
|
129
|
+
|
|
130
|
+
request = {
|
|
131
|
+
:method => method,
|
|
132
|
+
:url => uri,
|
|
133
|
+
:payload => payload,
|
|
134
|
+
:headers => headers}
|
|
135
|
+
|
|
136
|
+
if @cache and request[:method] == :get
|
|
137
|
+
raw = cached(request)
|
|
138
|
+
else
|
|
139
|
+
raw = execute(request)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
return raw if keep_raw
|
|
143
|
+
json = JSON.parse(raw)
|
|
144
|
+
rescue JSON::ParserError
|
|
145
|
+
return raw
|
|
146
|
+
rescue RestClient::RequestFailed => ex
|
|
147
|
+
raise appropriate_error(ex)
|
|
148
|
+
rescue RestClient::ResourceNotFound => ex
|
|
149
|
+
raise Error::ResourceNotFound, request[:url], ex.backtrace
|
|
150
|
+
rescue Errno::ECONNREFUSED
|
|
151
|
+
raise Error::ConnectionRefused, "Is CouchDB running at #{@uri}?"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def execute(request)
|
|
155
|
+
RestClient::Request.execute(request)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def appropriate_error(exception)
|
|
159
|
+
body = exception.response.body if exception.respond_to?(:response)
|
|
160
|
+
backtrace = exception.backtrace
|
|
161
|
+
|
|
162
|
+
raise(Error::RequestFailed, exception.message, backtrace) unless body
|
|
163
|
+
raise(Error::RequestFailed, exception.message, backtrace) if body.empty?
|
|
164
|
+
|
|
165
|
+
json = JSON.parse(body)
|
|
166
|
+
error, reason = json['error'], json['reason']
|
|
167
|
+
|
|
168
|
+
case error
|
|
169
|
+
when 'bad_request'
|
|
170
|
+
raise(Error::BadRequest, reason, backtrace)
|
|
171
|
+
when 'authorization'
|
|
172
|
+
raise(Error::Authorization, reason, backtrace)
|
|
173
|
+
when 'not_found'
|
|
174
|
+
raise(Error::NotFound, reason, backtrace)
|
|
175
|
+
when 'file_exists'
|
|
176
|
+
raise(Error::FileExists, reason, backtrace)
|
|
177
|
+
when 'missing_rev'
|
|
178
|
+
raise(Error::MissingRevision, reason, backtrace)
|
|
179
|
+
when 'conflict'
|
|
180
|
+
raise(Error::Conflict, reason, backtrace)
|
|
181
|
+
else
|
|
182
|
+
raise(Error::RequestFailed, json.inspect, backtrace)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
JSON_PARAMS = %w[key startkey endkey]
|
|
187
|
+
|
|
188
|
+
def paramify(hash)
|
|
189
|
+
hash.map{|k,v|
|
|
190
|
+
k = k.to_s
|
|
191
|
+
v = v.to_json if JSON_PARAMS.include?(k)
|
|
192
|
+
"#{Makura.escape(k)}=#{Makura.escape(v)}"
|
|
193
|
+
}.join('&')
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def uri(path = '/', params = {})
|
|
197
|
+
uri = @uri.dup
|
|
198
|
+
uri.path = (path[0,1] == '/' ? path : "/#{path}").squeeze('/')
|
|
199
|
+
uri.query = paramify(params) unless params.empty?
|
|
200
|
+
uri
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Makura
|
|
2
|
+
class UUIDCache
|
|
3
|
+
attr_accessor :min, :max, :server, :pretty
|
|
4
|
+
|
|
5
|
+
def initialize(server, min = 500, max = 1500, pretty = true)
|
|
6
|
+
@server, @min, @max, @pretty = server, min, max, pretty
|
|
7
|
+
@uuids = []
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def next
|
|
11
|
+
fetch if @uuids.size < min
|
|
12
|
+
@uuids.shift
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def fetch(count = 0)
|
|
16
|
+
todo = max - @uuids.size
|
|
17
|
+
count = [min, todo, max].sort[1]
|
|
18
|
+
uuids = @server.get('/_uuids', :count => count)['uuids']
|
|
19
|
+
uuids.map!{|u| Makura.pretty_from_md5(u) } if pretty
|
|
20
|
+
@uuids.concat(uuids)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/makura.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{makura}
|
|
5
|
+
s.version = "2009.05.27"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Michael 'manveru' Fellinger"]
|
|
9
|
+
s.date = %q{2009-05-27}
|
|
10
|
+
s.default_executable = %q{makura}
|
|
11
|
+
s.email = %q{m.fellinger@gmail.com}
|
|
12
|
+
s.executables = ["makura"]
|
|
13
|
+
s.files = ["CHANGELOG", "COPYING", "MANIFEST", "README.md", "Rakefile", "bin/makura", "example/blog.rb", "example/couch/map/author_all.js", "example/couch/map/author_posts.js", "example/couch/map/post_all.js", "example/couch/map/post_comments.js", "example/couch/reduce/sum_length.js", "lib/makura.rb", "lib/makura/database.rb", "lib/makura/design.rb", "lib/makura/error.rb", "lib/makura/http_methods.rb", "lib/makura/layout.rb", "lib/makura/model.rb", "lib/makura/plugin/localize.rb", "lib/makura/plugin/pager.rb", "lib/makura/server.rb", "lib/makura/uuid_cache.rb", "lib/makura/version.rb", "makura.gemspec", "tasks/authors.rake", "tasks/bacon.rake", "tasks/changelog.rake", "tasks/copyright.rake", "tasks/gem.rake", "tasks/gem_installer.rake", "tasks/git.rake", "tasks/grancher.rake", "tasks/manifest.rake", "tasks/metric_changes.rake", "tasks/rcov.rake", "tasks/release.rake", "tasks/reversion.rake", "tasks/todo.rake", "tasks/traits.rake", "tasks/yard.rake", "tasks/ycov.rake"]
|
|
14
|
+
s.homepage = %q{http://github.com/manveru/makura}
|
|
15
|
+
s.require_paths = ["lib"]
|
|
16
|
+
s.rubygems_version = %q{1.3.3}
|
|
17
|
+
s.summary = %q{Ruby wrapper around the CouchDB REST API.}
|
|
18
|
+
|
|
19
|
+
if s.respond_to? :specification_version then
|
|
20
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
21
|
+
s.specification_version = 3
|
|
22
|
+
|
|
23
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
24
|
+
s.add_runtime_dependency(%q<rest-client>, [">= 0.8.1"])
|
|
25
|
+
else
|
|
26
|
+
s.add_dependency(%q<rest-client>, [">= 0.8.1"])
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
s.add_dependency(%q<rest-client>, [">= 0.8.1"])
|
|
30
|
+
end
|
|
31
|
+
end
|
data/tasks/authors.rake
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Once git has a fix for the glibc in handling .mailmap and another fix for
|
|
2
|
+
# allowing empty mail address to be mapped in .mailmap we won't have to handle
|
|
3
|
+
# them manually.
|
|
4
|
+
|
|
5
|
+
desc 'Update AUTHORS'
|
|
6
|
+
task :authors do
|
|
7
|
+
authors = Hash.new(0)
|
|
8
|
+
|
|
9
|
+
`git shortlog -nse`.scan(/(\d+)\s(.+)\s<(.*)>$/) do |count, name, email|
|
|
10
|
+
case name
|
|
11
|
+
when "ahoward"
|
|
12
|
+
name, email = "Ara T. Howard", "ara.t.howard@gmail.com"
|
|
13
|
+
when "Martin Hilbig blueonyx@dev-area.net"
|
|
14
|
+
name, email = "Martin Hilbig", "blueonyx@dev-area.net"
|
|
15
|
+
when "Michael Fellinger m.fellinger@gmail.com"
|
|
16
|
+
name, email = "Michael Fellinger", "m.fellinger@gmail.com"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
authors[[name, email]] += count.to_i
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
File.open('AUTHORS', 'w+') do |io|
|
|
23
|
+
io.puts "Following persons have contributed to #{GEMSPEC.name}."
|
|
24
|
+
io.puts '(Sorted by number of submitted patches, then alphabetically)'
|
|
25
|
+
io.puts ''
|
|
26
|
+
authors.sort_by{|(n,e),c| [-c, n.downcase] }.each do |(name, email), count|
|
|
27
|
+
io.puts("%6d %s <%s>" % [count, name, email])
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/tasks/bacon.rake
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
desc 'Run all bacon specs with pretty output'
|
|
2
|
+
task :bacon => :install_dependencies do
|
|
3
|
+
require 'open3'
|
|
4
|
+
require 'scanf'
|
|
5
|
+
require 'matrix'
|
|
6
|
+
|
|
7
|
+
specs = PROJECT_SPECS
|
|
8
|
+
|
|
9
|
+
some_failed = false
|
|
10
|
+
specs_size = specs.size
|
|
11
|
+
len = specs.map{|s| s.size }.sort.last
|
|
12
|
+
total_tests = total_assertions = total_failures = total_errors = 0
|
|
13
|
+
totals = Vector[0, 0, 0, 0]
|
|
14
|
+
|
|
15
|
+
red, yellow, green = "\e[31m%s\e[0m", "\e[33m%s\e[0m", "\e[32m%s\e[0m"
|
|
16
|
+
left_format = "%4d/%d: %-#{len + 11}s"
|
|
17
|
+
spec_format = "%d specifications (%d requirements), %d failures, %d errors"
|
|
18
|
+
|
|
19
|
+
specs.each_with_index do |spec, idx|
|
|
20
|
+
print(left_format % [idx + 1, specs_size, spec])
|
|
21
|
+
|
|
22
|
+
Open3.popen3(RUBY, spec) do |sin, sout, serr|
|
|
23
|
+
out = sout.read.strip
|
|
24
|
+
err = serr.read.strip
|
|
25
|
+
|
|
26
|
+
# this is conventional, see spec/innate/state/fiber.rb for usage
|
|
27
|
+
if out =~ /^Bacon::Error: (needed .*)/
|
|
28
|
+
puts(yellow % ("%6s %s" % ['', $1]))
|
|
29
|
+
else
|
|
30
|
+
total = nil
|
|
31
|
+
|
|
32
|
+
out.each_line do |line|
|
|
33
|
+
scanned = line.scanf(spec_format)
|
|
34
|
+
|
|
35
|
+
next unless scanned.size == 4
|
|
36
|
+
|
|
37
|
+
total = Vector[*scanned]
|
|
38
|
+
break
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
if total
|
|
42
|
+
totals += total
|
|
43
|
+
tests, assertions, failures, errors = total_array = total.to_a
|
|
44
|
+
|
|
45
|
+
if tests > 0 && failures + errors == 0
|
|
46
|
+
puts((green % "%6d passed") % tests)
|
|
47
|
+
else
|
|
48
|
+
some_failed = true
|
|
49
|
+
puts(red % " failed")
|
|
50
|
+
puts out unless out.empty?
|
|
51
|
+
puts err unless err.empty?
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
some_failed = true
|
|
55
|
+
puts(red % " failed")
|
|
56
|
+
puts out unless out.empty?
|
|
57
|
+
puts err unless err.empty?
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
total_color = some_failed ? red : green
|
|
64
|
+
puts(total_color % (spec_format % totals.to_a))
|
|
65
|
+
exit 1 if some_failed
|
|
66
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
desc 'update changelog'
|
|
2
|
+
task :changelog do
|
|
3
|
+
File.open('CHANGELOG', 'w+') do |changelog|
|
|
4
|
+
`git log -z --abbrev-commit`.split("\0").each do |commit|
|
|
5
|
+
next if commit =~ /^Merge: \d*/
|
|
6
|
+
ref, author, time, _, title, _, message = commit.split("\n", 7)
|
|
7
|
+
ref = ref[/commit ([0-9a-f]+)/, 1]
|
|
8
|
+
author = author[/Author: (.*)/, 1].strip
|
|
9
|
+
time = Time.parse(time[/Date: (.*)/, 1]).utc
|
|
10
|
+
title.strip!
|
|
11
|
+
|
|
12
|
+
changelog.puts "[#{ref} | #{time}] #{author}"
|
|
13
|
+
changelog.puts '', " * #{title}"
|
|
14
|
+
changelog.puts '', message.rstrip if message
|
|
15
|
+
changelog.puts
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
desc "add copyright to all .rb files in the distribution"
|
|
2
|
+
task :copyright do
|
|
3
|
+
ignore = File.readlines('doc/LEGAL').
|
|
4
|
+
select{|line| line.strip!; File.exist?(line)}.
|
|
5
|
+
map{|file| File.expand_path(file)}
|
|
6
|
+
|
|
7
|
+
puts "adding copyright to files that don't have it currently"
|
|
8
|
+
puts PROJECT_COPYRIGHT
|
|
9
|
+
puts
|
|
10
|
+
|
|
11
|
+
Dir['{lib,test}/**/*{.rb}'].each do |file|
|
|
12
|
+
file = File.expand_path(file)
|
|
13
|
+
next if ignore.include? file
|
|
14
|
+
lines = File.readlines(file).map{|l| l.chomp}
|
|
15
|
+
unless lines.first(PROJECT_COPYRIGHT.size) == PROJECT_COPYRIGHT
|
|
16
|
+
puts "#{file} seems to need attention, first 4 lines:"
|
|
17
|
+
puts lines[0..3]
|
|
18
|
+
puts
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|