sql_tree 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/LICENSE +20 -0
- data/README.rdoc +25 -0
- data/Rakefile +5 -0
- data/lib/sql_tree.rb +42 -0
- data/lib/sql_tree/node.rb +37 -0
- data/lib/sql_tree/node/expression.rb +240 -0
- data/lib/sql_tree/node/field.rb +50 -0
- data/lib/sql_tree/node/join.rb +50 -0
- data/lib/sql_tree/node/select_expression.rb +45 -0
- data/lib/sql_tree/node/select_query.rb +78 -0
- data/lib/sql_tree/node/source.rb +37 -0
- data/lib/sql_tree/node/table_reference.rb +34 -0
- data/lib/sql_tree/node/value.rb +37 -0
- data/lib/sql_tree/node/variable.rb +35 -0
- data/lib/sql_tree/parser.rb +63 -0
- data/lib/sql_tree/token.rb +131 -0
- data/lib/sql_tree/tokenizer.rb +174 -0
- data/spec/integration/api_spec.rb +5 -0
- data/spec/integration/full_queries_spec.rb +21 -0
- data/spec/lib/matchers.rb +84 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/unit/expression_node_spec.rb +102 -0
- data/spec/unit/leaf_node_spec.rb +84 -0
- data/spec/unit/select_query_spec.rb +52 -0
- data/spec/unit/tokenizer_spec.rb +86 -0
- data/sql_tree.gemspec +27 -0
- data/tasks/github-gem.rake +323 -0
- metadata +92 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../spec_helper"
|
2
|
+
|
3
|
+
describe SQLTree::Node::Source do
|
4
|
+
|
5
|
+
it "should parse the table name correctly" do
|
6
|
+
SQLTree::Node::Source['table AS a'].table.should == 'table'
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should parse the alias correctly when using the AS keyword" do
|
10
|
+
SQLTree::Node::Source['table AS a'].table_alias.should == 'a'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should not require the AS keyword for a table alias" do
|
14
|
+
SQLTree::Node::Source['table AS a'].should == SQLTree::Node::Source['table a']
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should parse a table name without alias" do
|
18
|
+
SQLTree::Node::Source['table'].table.should == "table"
|
19
|
+
SQLTree::Node::Source['table'].table_alias.should be_nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should have no joins" do
|
23
|
+
SQLTree::Node::Source['table'].joins.should be_empty
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe SQLTree::Node::Join do
|
28
|
+
|
29
|
+
it "should parse a join table" do
|
30
|
+
SQLTree::Node::Join['LEFT JOIN table ON other.field = table.field'].table.should == 'table'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should parse the join type" do
|
34
|
+
SQLTree::Node::Join['LEFT JOIN table ON other.field = table.field'].join_type.should == :left
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should parse the join expression" do
|
38
|
+
SQLTree::Node::Join['LEFT JOIN table ON other.field = table.field'].join_expression.should be_kind_of(SQLTree::Node::Expression)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should not parse a table alias" do
|
42
|
+
SQLTree::Node::Join['LEFT JOIN table ON other.field = table.field'].table_alias.should be_nil
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should parse a table alias with AS" do
|
46
|
+
SQLTree::Node::Join['LEFT JOIN table AS t ON other.field = table.field'].table_alias.should == 't'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should parse a table alias without AS" do
|
50
|
+
SQLTree::Node::Join['LEFT JOIN table t ON other.field = table.field'].table_alias.should == 't'
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../spec_helper"
|
2
|
+
|
3
|
+
describe SQLTree::Tokenizer do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@tokenizer = SQLTree::Tokenizer.new
|
7
|
+
end
|
8
|
+
|
9
|
+
context "recognizing single tokens" do
|
10
|
+
it "should tokenize SQL query keywords" do
|
11
|
+
@tokenizer.tokenize('WHERE').should tokenize_to(:where)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should tokenize expression keywords" do
|
15
|
+
@tokenizer.tokenize('and').should tokenize_to(:and)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should tokenize muliple separate keywords" do
|
19
|
+
@tokenizer.tokenize('SELECT DISTINCT').should tokenize_to(:select, :distinct)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should ignore excessive whitespace" do
|
23
|
+
@tokenizer.tokenize("\tSELECT DISTINCT \r\r").should tokenize_to(:select, :distinct)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should tokenize variables" do
|
27
|
+
@tokenizer.tokenize("var").should tokenize_to(sql_var('var'))
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should tokenize quoted variables" do
|
31
|
+
@tokenizer.tokenize('"var"').should tokenize_to(sql_var('var'))
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should tokenize quoted variables even when they are a reserved keyword" do
|
35
|
+
@tokenizer.tokenize('"where"').should tokenize_to(sql_var('where'))
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should tokenize strings" do
|
39
|
+
@tokenizer.tokenize("'hello' ' world '").should tokenize_to('hello', ' world ')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should tokenize numbers" do
|
43
|
+
@tokenizer.tokenize("1 -2 3.14 -4.0").should tokenize_to(1, -2, 3.14, -4.0)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should tokenize logical operators" do
|
47
|
+
@tokenizer.tokenize("< = <> >=").should tokenize_to(:lt, :eq, :ne, :gte)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should tokenize arithmetic operators" do
|
51
|
+
@tokenizer.tokenize("+ - / * %").should tokenize_to(:plus, :minus, :divide, :multiply, :modulo)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should tokenize parentheses" do
|
55
|
+
@tokenizer.tokenize("(a)").should tokenize_to(lparen, sql_var('a'), rparen)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should tokenize dots" do
|
59
|
+
@tokenizer.tokenize('a."b"').should tokenize_to(sql_var('a'), dot, sql_var('b'))
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should tokenize commas" do
|
63
|
+
@tokenizer.tokenize('a , "b"').should tokenize_to(sql_var('a'), comma, sql_var('b'))
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# # Combined tokens are disabled for now;
|
68
|
+
# # Combination is currently done in the parsing phase.
|
69
|
+
# context "combining double keywords" do
|
70
|
+
# it "should tokenize double keywords" do
|
71
|
+
# @tokenizer.tokenize('NOT LIKE').should tokenize_to(:not_like)
|
72
|
+
# end
|
73
|
+
# end
|
74
|
+
|
75
|
+
context "when tokenizing full queries or query fragments" do
|
76
|
+
it "should tokenize a full SQL query" do
|
77
|
+
@tokenizer.tokenize("SELECT a.* FROM a_table AS a WHERE a.id > 1").should tokenize_to(
|
78
|
+
:select, sql_var('a'), dot, :multiply, :from, sql_var('a_table'), :as, sql_var('a'), :where, sql_var('a'), dot, sql_var('id'), :gt, 1)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should tokenize a function call" do
|
82
|
+
@tokenizer.tokenize("MD5('test')").should tokenize_to(sql_var('MD5'), lparen, 'test', rparen)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
data/sql_tree.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'sql_tree'
|
3
|
+
|
4
|
+
# Do not modify the version and date values by hand, because this will
|
5
|
+
# automatically by them gem release script.
|
6
|
+
s.version = '0.0.1'
|
7
|
+
s.date = "2009-10-09"
|
8
|
+
|
9
|
+
s.summary = "A pure Ruby library to represent SQL queries with a syntax tree for inspection and modification."
|
10
|
+
s.description = <<-EOS
|
11
|
+
The library can parse an SQL query (a string) to represent the query using
|
12
|
+
a syntax tree, and it can generate an SQL query from a syntax tree. The
|
13
|
+
syntax tree ca be used to inspect to query, or to modify it.
|
14
|
+
EOS
|
15
|
+
|
16
|
+
s.authors = 'Willem van Bergen'
|
17
|
+
s.email = 'willem@vanbergen.org'
|
18
|
+
s.homepage = 'http://wiki.github.com/wvanbergen/sql_tree'
|
19
|
+
|
20
|
+
s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
|
21
|
+
s.extra_rdoc_files = ['README.rdoc']
|
22
|
+
|
23
|
+
# Do not modify the files and test_files values by hand, because this will
|
24
|
+
# automatically by them gem release script.
|
25
|
+
s.files = %w(spec/unit/select_query_spec.rb spec/spec_helper.rb lib/sql_tree/tokenizer.rb lib/sql_tree/node/variable.rb lib/sql_tree/node/join.rb .gitignore LICENSE spec/lib/matchers.rb spec/integration/full_queries_spec.rb lib/sql_tree/parser.rb sql_tree.gemspec spec/unit/tokenizer_spec.rb spec/unit/expression_node_spec.rb lib/sql_tree/node/select_expression.rb spec/unit/leaf_node_spec.rb lib/sql_tree/token.rb lib/sql_tree/node/table_reference.rb lib/sql_tree/node/source.rb lib/sql_tree/node/field.rb Rakefile tasks/github-gem.rake lib/sql_tree/node/select_query.rb lib/sql_tree/node.rb README.rdoc spec/integration/api_spec.rb lib/sql_tree/node/value.rb lib/sql_tree/node/expression.rb lib/sql_tree.rb)
|
26
|
+
s.test_files = %w(spec/unit/select_query_spec.rb spec/integration/full_queries_spec.rb spec/unit/tokenizer_spec.rb spec/unit/expression_node_spec.rb spec/unit/leaf_node_spec.rb spec/integration/api_spec.rb)
|
27
|
+
end
|
@@ -0,0 +1,323 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/tasklib'
|
4
|
+
require 'date'
|
5
|
+
require 'git'
|
6
|
+
|
7
|
+
module GithubGem
|
8
|
+
|
9
|
+
# Detects the gemspc file of this project using heuristics.
|
10
|
+
def self.detect_gemspec_file
|
11
|
+
FileList['*.gemspec'].first
|
12
|
+
end
|
13
|
+
|
14
|
+
# Detects the main include file of this project using heuristics
|
15
|
+
def self.detect_main_include
|
16
|
+
if detect_gemspec_file =~ /^(\.*)\.gemspec$/ && File.exist?("lib/#{$1}.rb")
|
17
|
+
"lib/#{$1}.rb"
|
18
|
+
elsif FileList['lib/*.rb'].length == 1
|
19
|
+
FileList['lib/*.rb'].first
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class RakeTasks
|
26
|
+
|
27
|
+
attr_reader :gemspec, :modified_files, :git
|
28
|
+
attr_accessor :gemspec_file, :task_namespace, :main_include, :root_dir, :spec_pattern, :test_pattern, :remote, :remote_branch, :local_branch
|
29
|
+
|
30
|
+
# Initializes the settings, yields itself for configuration
|
31
|
+
# and defines the rake tasks based on the gemspec file.
|
32
|
+
def initialize(task_namespace = :gem)
|
33
|
+
@gemspec_file = GithubGem.detect_gemspec_file
|
34
|
+
@task_namespace = task_namespace
|
35
|
+
@main_include = GithubGem.detect_main_include
|
36
|
+
@modified_files = []
|
37
|
+
@root_dir = Dir.pwd
|
38
|
+
@test_pattern = 'test/**/*_test.rb'
|
39
|
+
@spec_pattern = 'spec/**/*_spec.rb'
|
40
|
+
@local_branch = 'master'
|
41
|
+
@remote = 'origin'
|
42
|
+
@remote_branch = 'master'
|
43
|
+
|
44
|
+
yield(self) if block_given?
|
45
|
+
|
46
|
+
@git = Git.open(@root_dir)
|
47
|
+
load_gemspec!
|
48
|
+
define_tasks!
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
# Define Unit test tasks
|
54
|
+
def define_test_tasks!
|
55
|
+
require 'rake/testtask'
|
56
|
+
|
57
|
+
namespace(:test) do
|
58
|
+
Rake::TestTask.new(:basic) do |t|
|
59
|
+
t.pattern = test_pattern
|
60
|
+
t.verbose = true
|
61
|
+
t.libs << 'test'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
desc "Run all unit tests for #{gemspec.name}"
|
66
|
+
task(:test => ['test:basic'])
|
67
|
+
end
|
68
|
+
|
69
|
+
# Defines RSpec tasks
|
70
|
+
def define_rspec_tasks!
|
71
|
+
require 'spec/rake/spectask'
|
72
|
+
|
73
|
+
namespace(:spec) do
|
74
|
+
desc "Verify all RSpec examples for #{gemspec.name}"
|
75
|
+
Spec::Rake::SpecTask.new(:basic) do |t|
|
76
|
+
t.spec_files = FileList[spec_pattern]
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Verify all RSpec examples for #{gemspec.name} and output specdoc"
|
80
|
+
Spec::Rake::SpecTask.new(:specdoc) do |t|
|
81
|
+
t.spec_files = FileList[spec_pattern]
|
82
|
+
t.spec_opts << '--format' << 'specdoc' << '--color'
|
83
|
+
end
|
84
|
+
|
85
|
+
desc "Run RCov on specs for #{gemspec.name}"
|
86
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
87
|
+
t.spec_files = FileList[spec_pattern]
|
88
|
+
t.rcov = true
|
89
|
+
t.rcov_opts = ['--exclude', '"spec/*,gems/*"', '--rails']
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
desc "Verify all RSpec examples for #{gemspec.name} and output specdoc"
|
94
|
+
task(:spec => ['spec:specdoc'])
|
95
|
+
end
|
96
|
+
|
97
|
+
# Defines the rake tasks
|
98
|
+
def define_tasks!
|
99
|
+
|
100
|
+
define_test_tasks! if has_tests?
|
101
|
+
define_rspec_tasks! if has_specs?
|
102
|
+
|
103
|
+
namespace(@task_namespace) do
|
104
|
+
desc "Updates the filelist in the gemspec file"
|
105
|
+
task(:manifest) { manifest_task }
|
106
|
+
|
107
|
+
desc "Builds the .gem package"
|
108
|
+
task(:build => :manifest) { build_task }
|
109
|
+
|
110
|
+
desc "Sets the version of the gem in the gemspec"
|
111
|
+
task(:set_version => [:check_version, :check_current_branch]) { version_task }
|
112
|
+
task(:check_version => :fetch_origin) { check_version_task }
|
113
|
+
|
114
|
+
task(:fetch_origin) { fetch_origin_task }
|
115
|
+
task(:check_current_branch) { check_current_branch_task }
|
116
|
+
task(:check_clean_status) { check_clean_status_task }
|
117
|
+
task(:check_not_diverged => :fetch_origin) { check_not_diverged_task }
|
118
|
+
|
119
|
+
checks = [:check_current_branch, :check_clean_status, :check_not_diverged, :check_version]
|
120
|
+
checks.unshift('spec:basic') if has_specs?
|
121
|
+
checks.unshift('test:basic') if has_tests?
|
122
|
+
checks.push << [:check_rubyforge] if gemspec.rubyforge_project
|
123
|
+
|
124
|
+
desc "Perform all checks that would occur before a release"
|
125
|
+
task(:release_checks => checks)
|
126
|
+
|
127
|
+
release_tasks = [:release_checks, :set_version, :build, :github_release]
|
128
|
+
release_tasks << [:rubyforge_release] if gemspec.rubyforge_project
|
129
|
+
|
130
|
+
desc "Release a new verison of the gem"
|
131
|
+
task(:release => release_tasks) { release_task }
|
132
|
+
|
133
|
+
task(:check_rubyforge) { check_rubyforge_task }
|
134
|
+
task(:rubyforge_release) { rubyforge_release_task }
|
135
|
+
task(:github_release => [:commit_modified_files, :tag_version]) { github_release_task }
|
136
|
+
task(:tag_version) { tag_version_task }
|
137
|
+
task(:commit_modified_files) { commit_modified_files_task }
|
138
|
+
|
139
|
+
desc "Updates the gem release tasks with the latest version on Github"
|
140
|
+
task(:update_tasks) { update_tasks_task }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Updates the files list and test_files list in the gemspec file using the list of files
|
145
|
+
# in the repository and the spec/test file pattern.
|
146
|
+
def manifest_task
|
147
|
+
# Load all the gem's files using "git ls-files"
|
148
|
+
repository_files = git.ls_files.keys
|
149
|
+
test_files = Dir[test_pattern] + Dir[spec_pattern]
|
150
|
+
|
151
|
+
update_gemspec(:files, repository_files)
|
152
|
+
update_gemspec(:test_files, repository_files & test_files)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Builds the gem
|
156
|
+
def build_task
|
157
|
+
sh "gem build -q #{gemspec_file}"
|
158
|
+
Dir.mkdir('pkg') unless File.exist?('pkg')
|
159
|
+
sh "mv #{gemspec.name}-#{gemspec.version}.gem pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
160
|
+
end
|
161
|
+
|
162
|
+
# Updates the version number in the gemspec file, the VERSION constant in the main
|
163
|
+
# include file and the contents of the VERSION file.
|
164
|
+
def version_task
|
165
|
+
update_gemspec(:version, ENV['VERSION']) if ENV['VERSION']
|
166
|
+
update_gemspec(:date, Date.today)
|
167
|
+
|
168
|
+
update_version_file(gemspec.version)
|
169
|
+
update_version_constant(gemspec.version)
|
170
|
+
end
|
171
|
+
|
172
|
+
def check_version_task
|
173
|
+
raise "#{ENV['VERSION']} is not a valid version number!" if ENV['VERSION'] && !Gem::Version.correct?(ENV['VERSION'])
|
174
|
+
proposed_version = Gem::Version.new(ENV['VERSION'] || gemspec.version)
|
175
|
+
# Loads the latest version number using the created tags
|
176
|
+
newest_version = git.tags.map { |tag| tag.name.split('-').last }.compact.map { |v| Gem::Version.new(v) }.max
|
177
|
+
raise "This version (#{proposed_version}) is not higher than the highest tagged version (#{newest_version})" if newest_version && newest_version >= proposed_version
|
178
|
+
end
|
179
|
+
|
180
|
+
# Checks whether the current branch is not diverged from the remote branch
|
181
|
+
def check_not_diverged_task
|
182
|
+
raise "The current branch is diverged from the remote branch!" if git.log.between('HEAD', git.remote(remote).branch(remote_branch).gcommit).any?
|
183
|
+
end
|
184
|
+
|
185
|
+
# Checks whether the repository status ic clean
|
186
|
+
def check_clean_status_task
|
187
|
+
raise "The current working copy contains modifications" if git.status.changed.any?
|
188
|
+
end
|
189
|
+
|
190
|
+
# Checks whether the current branch is correct
|
191
|
+
def check_current_branch_task
|
192
|
+
raise "Currently not on #{local_branch} branch!" unless git.branch.name == local_branch.to_s
|
193
|
+
end
|
194
|
+
|
195
|
+
# Fetches the latest updates from Github
|
196
|
+
def fetch_origin_task
|
197
|
+
git.fetch('origin')
|
198
|
+
end
|
199
|
+
|
200
|
+
# Commits every file that has been changed by the release task.
|
201
|
+
def commit_modified_files_task
|
202
|
+
if modified_files.any?
|
203
|
+
modified_files.each { |file| git.add(file) }
|
204
|
+
git.commit("Released #{gemspec.name} gem version #{gemspec.version}")
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Adds a tag for the released version
|
209
|
+
def tag_version_task
|
210
|
+
git.add_tag("#{gemspec.name}-#{gemspec.version}")
|
211
|
+
end
|
212
|
+
|
213
|
+
# Pushes the changes and tag to github
|
214
|
+
def github_release_task
|
215
|
+
git.push(remote, remote_branch, true)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Checks whether Rubyforge is configured properly
|
219
|
+
def check_rubyforge_task
|
220
|
+
# Login no longer necessary when using rubyforge 2.0.0 gem
|
221
|
+
# raise "Could not login on rubyforge!" unless `rubyforge login 2>&1`.strip.empty?
|
222
|
+
output = `rubyforge names`.split("\n")
|
223
|
+
raise "Rubyforge group not found!" unless output.any? { |line| %r[^groups\s*\:.*\b#{Regexp.quote(gemspec.rubyforge_project)}\b.*] =~ line }
|
224
|
+
raise "Rubyforge package not found!" unless output.any? { |line| %r[^packages\s*\:.*\b#{Regexp.quote(gemspec.name)}\b.*] =~ line }
|
225
|
+
end
|
226
|
+
|
227
|
+
# Task to release the .gem file toRubyforge.
|
228
|
+
def rubyforge_release_task
|
229
|
+
sh 'rubyforge', 'add_release', gemspec.rubyforge_project, gemspec.name, gemspec.version.to_s, "pkg/#{gemspec.name}-#{gemspec.version}.gem"
|
230
|
+
end
|
231
|
+
|
232
|
+
# Gem release task.
|
233
|
+
# All work is done by the task's dependencies, so just display a release completed message.
|
234
|
+
def release_task
|
235
|
+
puts
|
236
|
+
puts '------------------------------------------------------------'
|
237
|
+
puts "Released #{gemspec.name} version #{gemspec.version}"
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
# Checks whether this project has any RSpec files
|
243
|
+
def has_specs?
|
244
|
+
FileList[spec_pattern].any?
|
245
|
+
end
|
246
|
+
|
247
|
+
# Checks whether this project has any unit test files
|
248
|
+
def has_tests?
|
249
|
+
FileList[test_pattern].any?
|
250
|
+
end
|
251
|
+
|
252
|
+
# Loads the gemspec file
|
253
|
+
def load_gemspec!
|
254
|
+
@gemspec = eval(File.read(@gemspec_file))
|
255
|
+
end
|
256
|
+
|
257
|
+
# Updates the VERSION file with the new version
|
258
|
+
def update_version_file(version)
|
259
|
+
if File.exists?('VERSION')
|
260
|
+
File.open('VERSION', 'w') { |f| f << version.to_s }
|
261
|
+
modified_files << 'VERSION'
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Updates the VERSION constant in the main include file if it exists
|
266
|
+
def update_version_constant(version)
|
267
|
+
if main_include && File.exist?(main_include)
|
268
|
+
file_contents = File.read(main_include)
|
269
|
+
if file_contents.sub!(/^(\s+VERSION\s*=\s*)[^\s].*$/) { $1 + version.to_s.inspect }
|
270
|
+
File.open(main_include, 'w') { |f| f << file_contents }
|
271
|
+
modified_files << main_include
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Updates an attribute of the gemspec file.
|
277
|
+
# This function will open the file, and search/replace the attribute using a regular expression.
|
278
|
+
def update_gemspec(attribute, new_value, literal = false)
|
279
|
+
|
280
|
+
unless literal
|
281
|
+
new_value = case new_value
|
282
|
+
when Array then "%w(#{new_value.join(' ')})"
|
283
|
+
when Hash, String then new_value.inspect
|
284
|
+
when Date then new_value.strftime('%Y-%m-%d').inspect
|
285
|
+
else raise "Cannot write value #{new_value.inspect} to gemspec file!"
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
spec = File.read(gemspec_file)
|
290
|
+
regexp = Regexp.new('^(\s+\w+\.' + Regexp.quote(attribute.to_s) + '\s*=\s*)[^\s].*$')
|
291
|
+
if spec.sub!(regexp) { $1 + new_value }
|
292
|
+
File.open(gemspec_file, 'w') { |f| f << spec }
|
293
|
+
modified_files << gemspec_file
|
294
|
+
|
295
|
+
# Reload the gemspec so the changes are incorporated
|
296
|
+
load_gemspec!
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Updates the tasks file using the latest file found on Github
|
301
|
+
def update_tasks_task
|
302
|
+
require 'net/http'
|
303
|
+
|
304
|
+
server = 'github.com'
|
305
|
+
path = '/wvanbergen/github-gem/raw/master/tasks/github-gem.rake'
|
306
|
+
|
307
|
+
Net::HTTP.start(server) do |http|
|
308
|
+
response = http.get(path)
|
309
|
+
open(__FILE__, "w") { |file| file.write(response.body) }
|
310
|
+
end
|
311
|
+
|
312
|
+
relative_file = File.expand_path(__FILE__).sub(%r[^#{git.dir.path}/], '')
|
313
|
+
if git.status[relative_file] && git.status[relative_file].type == 'M'
|
314
|
+
git.add(relative_file)
|
315
|
+
git.commit("Updated to latest gem release management tasks.")
|
316
|
+
puts "Updated to latest version of gem release management tasks."
|
317
|
+
else
|
318
|
+
puts "Release managament tasks already are at the latest version."
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
323
|
+
end
|