hash_syntax 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Michael Edgar
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ = hash_syntax
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2011 Michael Edgar. See LICENSE for details.
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ require './lib/hash_syntax/version'
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "hash_syntax"
9
+ gem.summary = %Q{Converts Ruby files to and from Ruby 1.9's Hash syntax}
10
+ gem.description = %Q{The new label style for Ruby 1.9's literal hash keys
11
+ is somewhat controversial. This tool seamlessly converts Ruby files between
12
+ the old and the new syntaxes.}
13
+ gem.email = "michael.j.edgar@dartmouth.edu"
14
+ gem.homepage = "http://github.com/michaeledgar/hash_syntax"
15
+ gem.authors = ["Michael Edgar"]
16
+ gem.add_dependency 'object_regex', '~> 1.0.1'
17
+ gem.add_dependency 'trollop', '~> 1.16.2'
18
+ gem.add_development_dependency 'rspec', '>= 2.3.0'
19
+ gem.add_development_dependency "yard", ">= 0"
20
+ gem.version = HashSyntax::Version::STRING
21
+ end
22
+ Jeweler::GemcutterTasks.new
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
25
+ end
26
+
27
+ require 'rspec/core/rake_task'
28
+ RSpec::Core::RakeTask.new(:spec) do |spec|
29
+ spec.pattern = FileList['spec/**/*_spec.rb']
30
+ end
31
+
32
+ task :spec => :check_dependencies
33
+
34
+ task :default => :spec
35
+
36
+ begin
37
+ require 'yard'
38
+ YARD::Rake::YardocTask.new
39
+ rescue LoadError
40
+ task :yardoc do
41
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
42
+ end
43
+ end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby -w
2
+
3
+ require 'rubygems'
4
+ require 'hash_syntax'
5
+ HashSyntax::Runner.new.run!
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{hash_syntax}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Michael Edgar}]
12
+ s.date = %q{2011-06-24}
13
+ s.description = %q{The new label style for Ruby 1.9's literal hash keys
14
+ is somewhat controversial. This tool seamlessly converts Ruby files between
15
+ the old and the new syntaxes.}
16
+ s.email = %q{michael.j.edgar@dartmouth.edu}
17
+ s.executables = [%q{hash_syntax}]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE",
20
+ "README.rdoc"
21
+ ]
22
+ s.files = [
23
+ ".document",
24
+ "LICENSE",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "bin/hash_syntax",
28
+ "hash_syntax.gemspec",
29
+ "lib/hash_syntax.rb",
30
+ "lib/hash_syntax/runner.rb",
31
+ "lib/hash_syntax/token.rb",
32
+ "lib/hash_syntax/transformer.rb",
33
+ "lib/hash_syntax/version.rb",
34
+ "spec/hash_syntax_spec.rb",
35
+ "spec/spec.opts",
36
+ "spec/spec_helper.rb",
37
+ "spec/transformer_spec.rb"
38
+ ]
39
+ s.homepage = %q{http://github.com/michaeledgar/hash_syntax}
40
+ s.require_paths = [%q{lib}]
41
+ s.rubygems_version = %q{1.8.5}
42
+ s.summary = %q{Converts Ruby files to and from Ruby 1.9's Hash syntax}
43
+
44
+ if s.respond_to? :specification_version then
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
+ s.add_runtime_dependency(%q<object_regex>, ["~> 1.0.1"])
49
+ s.add_runtime_dependency(%q<trollop>, ["~> 1.16.2"])
50
+ s.add_development_dependency(%q<rspec>, [">= 2.3.0"])
51
+ s.add_development_dependency(%q<yard>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<object_regex>, ["~> 1.0.1"])
54
+ s.add_dependency(%q<trollop>, ["~> 1.16.2"])
55
+ s.add_dependency(%q<rspec>, [">= 2.3.0"])
56
+ s.add_dependency(%q<yard>, [">= 0"])
57
+ end
58
+ else
59
+ s.add_dependency(%q<object_regex>, ["~> 1.0.1"])
60
+ s.add_dependency(%q<trollop>, ["~> 1.16.2"])
61
+ s.add_dependency(%q<rspec>, [">= 2.3.0"])
62
+ s.add_dependency(%q<yard>, [">= 0"])
63
+ end
64
+ end
65
+
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby -w
2
+ require 'ripper'
3
+ require 'object_regex'
4
+ require 'trollop'
5
+
6
+ require 'hash_syntax/token'
7
+ require 'hash_syntax/runner'
8
+ require 'hash_syntax/transformer'
9
+ require 'hash_syntax/version'
@@ -0,0 +1,43 @@
1
+ module HashSyntax
2
+ class Runner
3
+
4
+ def run!
5
+ options = gather_options
6
+ validate_options(options)
7
+ files = gather_files
8
+ files.each do |name|
9
+ transformed_file = Transformer.transform(File.read(name), options)
10
+ File.open(name, 'w') { |fp| fp.write(transformed_file) }
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def gather_options
17
+ Trollop::options do
18
+ version HashSyntax::Version::STRING
19
+ banner <<-EOF
20
+ hash_syntax #{HashSyntax::Version::STRING} by Michael Edgar (adgar@carboni.ca)
21
+
22
+ Automatically convert hash symbol syntaxes in your Ruby code.
23
+ EOF
24
+ opt :"to-18", 'Convert to Ruby 1.8 syntax (:key => value)', :short => '-o'
25
+ opt :"to-19", 'Convert to Ruby 1.9 syntax (key: value)', :short => '-n'
26
+ end
27
+ end
28
+
29
+ def validate_options(opts)
30
+ Trollop::die 'Must specify --to_18 or --to_19' unless opts[:"to-18"] or opts[:"to-19"]
31
+ end
32
+
33
+ AUTO_SUBDIRS = %w(app ext features lib spec test)
34
+
35
+ def gather_files
36
+ if ARGV.empty?
37
+ AUTO_SUBDIRS.map { |dir| Dir["#{Dir.pwd}/#{dir}/**/*.rb"] }.flatten
38
+ else
39
+ ARGV
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ module HashSyntax
2
+ Token = Struct.new(:type, :body, :line, :col) do
3
+ # Unpacks the token from Ripper and breaks it into its separate components.
4
+ #
5
+ # @param [Array<Array<Integer, Integer>, Symbol, String>] token the token
6
+ # from Ripper that we're wrapping
7
+ def initialize(token)
8
+ (self.line, self.col), self.type, self.body = token
9
+ end
10
+
11
+ def width
12
+ body.size
13
+ end
14
+
15
+ def reg_desc
16
+ if type == :on_op && body == '=>'
17
+ 'hashrocket'
18
+ else
19
+ type.to_s.sub(/^on_/, '')
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,70 @@
1
+ module HashSyntax
2
+ module Transformer
3
+ MATCH_18 = ObjectRegex.new('symbeg (ident | kw) sp? hashrocket')
4
+ MATCH_19 = ObjectRegex.new('label')
5
+
6
+ extend self
7
+
8
+ def transform(input_text, options)
9
+ tokens = extract_tokens(input_text)
10
+ if options[:"to-18"]
11
+ transform_to_18(input_text, tokens, options)
12
+ elsif options[:"to-19"]
13
+ transform_to_19(input_text, tokens, options)
14
+ else
15
+ raise ArgumentError.new('Either :to_18 or :to_19 must be specified.')
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def extract_tokens(text)
22
+ swizzle_parser_flags do
23
+ Ripper.lex(text).map { |token| Token.new(token) }
24
+ end
25
+ end
26
+
27
+ def swizzle_parser_flags
28
+ old_w = $-w
29
+ old_v = $-v
30
+ old_d = $-d
31
+ $-w = $-v = $-d = false
32
+ yield
33
+ ensure
34
+ $-w = old_w
35
+ $-v = old_v
36
+ $-d = old_d
37
+ end
38
+
39
+ def transform_to_18(input_text, tokens, options)
40
+ lines = input_text.lines.to_a # eagerly expand lines
41
+ matches = MATCH_19.all_matches(tokens)
42
+ line_adjustments = Hash.new(0)
43
+ matches.each do |label_list|
44
+ label = label_list.first
45
+ lines[label.line - 1][label.col + line_adjustments[label.line],label.width] = ":#{label.body[0..-2]} =>"
46
+ line_adjustments[label.line] += 3 # " =>" is inserted and is 3 chars
47
+ end
48
+ lines.join
49
+ end
50
+
51
+ def transform_to_19(input_text, tokens, options)
52
+ lines = input_text.lines.to_a # eagerly expand lines
53
+ matches = MATCH_18.all_matches(tokens)
54
+ line_adjustments = Hash.new(0)
55
+ matches.each do |match_tokens|
56
+ symbeg, ident, *spacing_and_comments, rocket = match_tokens
57
+ lines[symbeg.line - 1][symbeg.col + line_adjustments[symbeg.line],1] = ''
58
+ lines[ident.line - 1].insert(ident.col + line_adjustments[ident.line] + ident.width - 1, ':')
59
+ lines[rocket.line - 1][rocket.col + line_adjustments[rocket.line],2] = ''
60
+ if spacing_and_comments.last != nil && spacing_and_comments.last.type == :on_sp
61
+ lines[rocket.line - 1][rocket.col + line_adjustments[rocket.line] - 1,1] = ''
62
+ line_adjustments[rocket.line] -= 3 # chomped " =>"
63
+ else
64
+ line_adjustments[rocket.line] -= 2 # only chomped the "=>"
65
+ end
66
+ end
67
+ lines.join
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,14 @@
1
+ module HashSyntax
2
+ module Version
3
+ MAJOR = 1
4
+ MINOR = 0
5
+ PATCH = 0
6
+ BUILD = ''
7
+
8
+ if BUILD.empty?
9
+ STRING = [MAJOR, MINOR, PATCH].compact.join('.')
10
+ else
11
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe "HashSyntax" do
4
+ it "has a version" do
5
+ HashSyntax::Version::STRING.should be >= "1.0.0"
6
+ end
7
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,22 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'hash_syntax'
4
+ require 'rspec'
5
+ require 'rspec/autorun'
6
+
7
+ RSpec::Matchers.define :transform_to do |output, target|
8
+ match do |input|
9
+ @result = HashSyntax::Transformer.transform(input, target => true)
10
+ @result == output
11
+ end
12
+
13
+ failure_message_for_should do |input|
14
+ "expected '#{input}' to correct to #{output}, not #{@result}"
15
+ end
16
+
17
+ diffable
18
+ end
19
+
20
+ RSpec.configure do |config|
21
+
22
+ end
@@ -0,0 +1,88 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe HashSyntax::Transformer do
4
+ describe 'transforming from 1.8 to 1.9 syntax' do
5
+ it 'can transform a simple hash' do
6
+ 'x = {:foo => :bar}'.should transform_to('x = {foo: :bar}', :to_19)
7
+ end
8
+
9
+ it 'transforms all hashes in a block of code' do
10
+ input = %q{
11
+ with_jumps_redirected(:break => ensure_body[1], :redo => ensure_body[1], :next => ensure_body[1],
12
+ :return => ensure_body[1], :rescue => ensure_body[1],
13
+ :yield_fail => ensure_body[1]) do
14
+ rescue_target, yield_fail_target =
15
+ build_rescue_target(node, result, rescue_body, ensure_block,
16
+ current_rescue, current_yield_fail)
17
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
18
+ end
19
+ }
20
+ output = %q{
21
+ with_jumps_redirected(break: ensure_body[1], redo: ensure_body[1], next: ensure_body[1],
22
+ return: ensure_body[1], rescue: ensure_body[1],
23
+ yield_fail: ensure_body[1]) do
24
+ rescue_target, yield_fail_target =
25
+ build_rescue_target(node, result, rescue_body, ensure_block,
26
+ current_rescue, current_yield_fail)
27
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
28
+ end
29
+ }
30
+ input.should transform_to(output, :to_19)
31
+ end
32
+
33
+ it 'transforms all hashes in a block of code without minding tight spacing' do
34
+ input = %q{
35
+ with_jumps_redirected(:break=>ensure_body[1], :redo=>ensure_body[1], :next=>ensure_body[1],
36
+ :return=>ensure_body[1], :rescue=>ensure_body[1],
37
+ :yield_fail=>ensure_body[1]) do
38
+ rescue_target, yield_fail_target =
39
+ build_rescue_target(node, result, rescue_body, ensure_block,
40
+ current_rescue, current_yield_fail)
41
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
42
+ end
43
+ }
44
+ output = %q{
45
+ with_jumps_redirected(break:ensure_body[1], redo:ensure_body[1], next:ensure_body[1],
46
+ return:ensure_body[1], rescue:ensure_body[1],
47
+ yield_fail:ensure_body[1]) do
48
+ rescue_target, yield_fail_target =
49
+ build_rescue_target(node, result, rescue_body, ensure_block,
50
+ current_rescue, current_yield_fail)
51
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
52
+ end
53
+ }
54
+ input.should transform_to(output, :to_19)
55
+ end
56
+
57
+ end
58
+
59
+ describe 'transforming from 1.9 to 1.8 syntax' do
60
+ it 'can transform a simple hash' do
61
+ 'x = {foo: :bar}'.should transform_to('x = {:foo => :bar}', :to_18)
62
+ end
63
+
64
+ it 'transforms all hashes in a block of code' do
65
+ input = %q{
66
+ with_jumps_redirected(break: ensure_body[1], redo: ensure_body[1], next: ensure_body[1],
67
+ return: ensure_body[1], rescue: ensure_body[1],
68
+ yield_fail: ensure_body[1]) do
69
+ rescue_target, yield_fail_target =
70
+ build_rescue_target(node, result, rescue_body, ensure_block,
71
+ current_rescue, current_yield_fail)
72
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
73
+ end
74
+ }
75
+ output = %q{
76
+ with_jumps_redirected(:break => ensure_body[1], :redo => ensure_body[1], :next => ensure_body[1],
77
+ :return => ensure_body[1], :rescue => ensure_body[1],
78
+ :yield_fail => ensure_body[1]) do
79
+ rescue_target, yield_fail_target =
80
+ build_rescue_target(node, result, rescue_body, ensure_block,
81
+ current_rescue, current_yield_fail)
82
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
83
+ end
84
+ }
85
+ input.should transform_to(output, :to_18)
86
+ end
87
+ end
88
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hash_syntax
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 1.0.0
6
+ platform: ruby
7
+ authors:
8
+ - Michael Edgar
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-06-24 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: object_regex
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.1
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: trollop
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 1.16.2
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: 2.3.0
46
+ type: :development
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: yard
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ type: :development
58
+ version_requirements: *id004
59
+ description: |-
60
+ The new label style for Ruby 1.9's literal hash keys
61
+ is somewhat controversial. This tool seamlessly converts Ruby files between
62
+ the old and the new syntaxes.
63
+ email: michael.j.edgar@dartmouth.edu
64
+ executables:
65
+ - hash_syntax
66
+ extensions: []
67
+
68
+ extra_rdoc_files:
69
+ - LICENSE
70
+ - README.rdoc
71
+ files:
72
+ - .document
73
+ - LICENSE
74
+ - README.rdoc
75
+ - Rakefile
76
+ - bin/hash_syntax
77
+ - hash_syntax.gemspec
78
+ - lib/hash_syntax.rb
79
+ - lib/hash_syntax/runner.rb
80
+ - lib/hash_syntax/token.rb
81
+ - lib/hash_syntax/transformer.rb
82
+ - lib/hash_syntax/version.rb
83
+ - spec/hash_syntax_spec.rb
84
+ - spec/spec.opts
85
+ - spec/spec_helper.rb
86
+ - spec/transformer_spec.rb
87
+ homepage: http://github.com/michaeledgar/hash_syntax
88
+ licenses: []
89
+
90
+ post_install_message:
91
+ rdoc_options: []
92
+
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: "0"
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: "0"
107
+ requirements: []
108
+
109
+ rubyforge_project:
110
+ rubygems_version: 1.8.5
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: Converts Ruby files to and from Ruby 1.9's Hash syntax
114
+ test_files: []
115
+