sas2yaml 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cdbfd522aa2b75913e825ff59ea05de81e35ce2d
4
+ data.tar.gz: bcb279dd496c036991a20d7aa1c22c359faab60e
5
+ SHA512:
6
+ metadata.gz: 38e7dc54d3467f37b1b7284539d2aa74ee3e3567f05cec458fed07aee69e0b2ecd7ea69d44d450f7859dad6fdda7c0602bde2f5fdb1e128c1016f955d8d1ba47
7
+ data.tar.gz: e40c5d66386bdedd659a6392e7ba40f6686675aa0723eb6c2264df041dda0f468e531a239243700c78334759c792808873cc0323fe1700796cd4a49c71710442
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.10.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sas2yaml.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Outcomes Insights, Inc.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Sas2Yaml
2
+
3
+ This gem installs a CLI program, `sas2yaml` which will (attempt) to read in a SAS input statement and turn it into a [YAML](http://yaml.org/) file with the name of each variable along with its position in a fixed-width file, length, and type (assuming that information is available).
4
+
5
+ This gem was developed in order to decipher the fixed-width file structure of SEER Medicare SAS input statement files and works (fairly) well in processing those files. Your mileage almost certainly will vary.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'sas2yaml'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install sas2yaml
22
+
23
+ ## Usage
24
+
25
+ ```
26
+ sas2yaml file1.sas file2.sas ...
27
+ ```
28
+
29
+ For each file listed, a lot of output will hit your screen, the program will hopefully not bomb out, and you'll end up with files named "file1.yml" and "file2.yml" (from the example above).
30
+
31
+ ## Development
32
+
33
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake false` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
34
+
35
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
36
+
37
+ ## Thanks
38
+ - [Outcomes Insights, Inc.](http://outins.com/)
39
+ - Many thanks for allowing me to release a portion of my work as Open Source Software!
40
+ - [Ruby](https://www.ruby-lang.org/en/)
41
+ - For being such an awesome language that it can pretend to be another (and much more awful) language **cough** *SAS* **cough**.
42
+
43
+
44
+ ## Contributing
45
+
46
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sas2yaml.
47
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sas2yaml"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/exe/sas2yaml ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "escort"
4
+ require "bundler/setup"
5
+ require "sas2yaml"
6
+
7
+ Escort::App.create do |app|
8
+ app.version Sas2Yaml::VERSION
9
+ app.summary Sas2Yaml::SUMMARY
10
+ app.description Sas2Yaml::DESCRIPTION
11
+
12
+ app.action do |options, arguments|
13
+ begin
14
+ Sas2Yaml::AssembleCommand.new(options, arguments).execute
15
+ rescue
16
+ puts $!.message
17
+ puts $!.backtrace.join("\n")
18
+ raise
19
+ end
20
+ end
21
+ end
data/lib/sas2yaml.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "sas2yaml/metadata"
2
+ require "sas2yaml/assemble_command"
3
+
4
+ module Sas2Yaml
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'sas_processor'
2
+ require_relative 'sassifier'
3
+ require 'psych'
4
+
5
+ module Sas2Yaml
6
+ class AssembleCommand < ::Escort::ActionCommand::Base
7
+ def execute
8
+ arguments.each do |sas_file|
9
+ puts "Processing #{sas_file}"
10
+ processed_sas = SasProcessor.new(sas_file).lines.join("\n")
11
+ sassy_file = File.join(Dir.tmpdir, File.basename(sas_file, '.*') + '.sassy')
12
+ File.write(sassy_file, processed_sas)
13
+ puts "Temp at #{sassy_file}"
14
+ sassy = Sassifier.new(processed_sas)
15
+ puts "NUM COLUMNS: #{sassy.hash.keys.length}"
16
+ file = sas_file.gsub(/\..+$/, '.yml')
17
+ File.write(file, sassy.hash.to_yaml)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ module Sas2Yaml
2
+ VERSION = "0.0.1"
3
+ SUMMARY = "Convert SAS Input files into YAML describing layout of the data"
4
+ DESCRIPTION = "Converts a SAS Input file into a YAML file which details each column along with its type, length, and start column."
5
+ end
6
+
@@ -0,0 +1,34 @@
1
+ # Script that drives processing each SAS file to glean the field type
2
+ # information e.g.
3
+ # Column position
4
+ # Length
5
+ # Format
6
+ # Data type
7
+
8
+ require 'psych'
9
+ require 'fileutils'
10
+ require 'tmpdir'
11
+
12
+ require_relative '../parsers/sas/sas_processor'
13
+ require_relative '../parsers/sas/sassifier'
14
+
15
+ module ProcessSas
16
+ extend self
17
+
18
+ def run
19
+ dir = 'ddls'
20
+ FileUtils.mkdir(dir) unless File.exist?(dir)
21
+ Dir.glob("sas/*").each do |sas_file|
22
+ puts "=" * 90
23
+ puts sas_file
24
+ puts "=" * 90
25
+ processed_sas = SasProcessor.new(sas_file).lines.join("\n")
26
+ sassy = Sassifier.new(processed_sas)
27
+ puts "NUM COLUMNS: #{sassy.hash.keys.length}"
28
+ file = File.join(dir, sas_file.gsub(/.+\//, '').gsub(/\..+$/, '.yml'))
29
+ File.open(file, 'w') { |f| f.puts sassy.hash.to_yaml }
30
+
31
+ File.write(File.join(Dir.tmpdir, File.basename(file, '.*') + '.sassy'), processed_sas)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ # Given an input of something like mon1-mon288
2
+ # will return %w(mon1 mon2 ... mon288) when #values is called
3
+ class Rangifier
4
+ TRAILING_DIGITS_REGEXP = /(\d+)$/
5
+ def initialize(input)
6
+ @input = input
7
+ end
8
+
9
+ def values
10
+ @values ||= get_values
11
+ end
12
+
13
+ private
14
+ def get_values
15
+ parts = @input.sub(/;/, '').strip.split('-').map(&:strip)
16
+ return [@input] unless parts.first =~ TRAILING_DIGITS_REGEXP
17
+ puts "Rangifying #@input => #{parts}"
18
+ first = parts.first.match(TRAILING_DIGITS_REGEXP)[1].to_i
19
+ last = parts.last.match(TRAILING_DIGITS_REGEXP)[1].to_i
20
+ prefix = parts.first.sub(TRAILING_DIGITS_REGEXP, '')
21
+ puts "Ranging #{prefix} from #{first} - #{last}"
22
+ (first..last).map { |i| "#{prefix}#{i}"}
23
+ end
24
+ end
@@ -0,0 +1,221 @@
1
+ require_relative 'rangifier'
2
+
3
+ # Translates SAS code into executable Ruby code
4
+ #
5
+ # This is a very gross translation and most code is skipped completely
6
+ # When I was looking at the SAS code to read in the ALL dataset, I noticed
7
+ # that I couldn't simply parse out each line and read the field information
8
+ # directly from the SAS file because sometimes the SAS file used loops
9
+ # to define the columns for some of the fields
10
+ #
11
+ # Also, some of the data type information was assigned to arrays in those
12
+ # loops.
13
+ #
14
+ # BUT I did notice that SAS looks a bit like Ruby and, with a little
15
+ # pruning and translating, the SAS code could be converted to Ruby
16
+ #
17
+ # So this class will parse a SAS file looking for the first line that
18
+ # starts with INPUT and will parse the file until it hits a line that
19
+ # says LABELs
20
+ #
21
+ # The resulting Ruby code uses instance variables to store all
22
+ # the information during processing. This is to avoid problems where the
23
+ # SAS code is using reserved words or method names in Ruby.
24
+ # The SAS code frequently uses variable names like "begin" and "end" which are
25
+ # reserved words in Ruby and "inc" and "pos" which are common method names
26
+ #
27
+ # See below for information about how certain lines are handled
28
+ class SasProcessor
29
+ @@def_regexp = /@[^;]/
30
+ @@array_regexp = /array/
31
+ @@label_start_regexp = /^label/i
32
+ @@comment_regexp =%r{/\*.*?\*/}m
33
+ @@blank_line_regexp = /^$/
34
+ @@mode = :skip
35
+ @@do_regexp = /^do /
36
+ @@equals_regexp = /=/
37
+ @@infile_regexp = /^infile\s+/i
38
+ @@op_regexp = %r{([+-/=*]+)}
39
+
40
+ def initialize(file_path)
41
+ @file_path = file_path
42
+ end
43
+
44
+ # Given blah01-blah02 or (blah01-blah02)
45
+ # Return ('blah01'..'blah02')
46
+ def rangify(range)
47
+ '%w(' + Rangifier.new(strip_parens(range)).values.join(' ') + ')'
48
+ end
49
+
50
+ # Given "(something)"
51
+ # Return "something"
52
+ def strip_parens(text)
53
+ text.gsub(/[()]/, '')
54
+ end
55
+
56
+ # Given what could either be a variable name or a number literal, returns
57
+ # either an instance variable with the same name, or the number literal
58
+ # "001" => "1"
59
+ # "var" => "@var"
60
+ # "12var34" => "@12var34"
61
+ def var_or_num(v_or_n)
62
+ return v_or_n.gsub(/^0+(\d)/,'\1') if /^\d+$/.match(v_or_n)
63
+ ivarify(v_or_n)
64
+ end
65
+
66
+ # Expect inputs like
67
+ # cred10 which we just return
68
+ # or (plan1-plan2) which we return as the range ('plan1'..'plan2')
69
+ # or some_arr(2) which we return as @some_arr[2]
70
+ def fix_name(text)
71
+ return "'#{text}'" unless /\(/.match(text)
72
+ return rangify(text) if /^\(/.match(text)
73
+ ivarify(text.gsub(/\(([^)]+)\)/) do |match|
74
+ '[' + var_or_num($1) + ']'
75
+ end)
76
+ end
77
+
78
+ # Prepends "@" to the string
79
+ def ivarify(var_name)
80
+ '@' + var_name
81
+ end
82
+
83
+ # Definition lines start with "@111" or "input @pos + 2"
84
+ # But either way, we're interested in everything after the @ sign
85
+ # for these lines
86
+ # Examples
87
+ # @012 bic $char2.
88
+ # input @inc2 dgn(j) $char5.
89
+ def translate_def(line)
90
+ # Strip up through the @
91
+ line.gsub!(/^.*@/, '')
92
+ parts = line.split(/\s+/)
93
+ # Type information is always the last word on the line
94
+ type = parts.pop
95
+ # The name is always the second to the last word on the line
96
+ name = fix_name(parts.pop)
97
+
98
+ # The rest of the line could be as simple as a number literal or something like
99
+ # (pos + 1)
100
+ # So we put spaces between all the operators and then translate each part
101
+ rest = blow_out_ops(strip_parens(parts.join(' '))).split(/\s+/).map { |w| var_or_num_or_op(w) }.join(' ')
102
+
103
+ # Spit out Ruby code that will tranlate the contents of this definition line
104
+ "at(#{rest}, #{name}, '#{type}')"
105
+ end
106
+
107
+ # SAS seems to be able to store input definitions into arrays
108
+ # I don't know the mechanism, but I know how to translate it
109
+ # We'll take a line like
110
+ # array dgn(10) $ dgn_cd1-dgn_cd10;
111
+ def translate_array(line)
112
+ parts = line.split('$')
113
+ # Last word has a ';' and then then a range that defines the field names
114
+ # assigned to this array
115
+ range = rangify(parts.pop.chop.sub(/^[\s\d]*/, ''))
116
+ parts = parts.first.split(/\s+/)
117
+ # We'll use the array's name as it appears in SAS to store the array
118
+ # of field names
119
+ # The array name starts as arr(10) so we'll chop off the part in parens
120
+ puts parts[1]
121
+ array_name = ivarify(parts[1].gsub(/\(.*/, ''))
122
+ puts array_name
123
+ # Spit out Ruby that assigns the array of field names to the array instance variable
124
+ "#{array_name} = #{range}"
125
+ end
126
+
127
+ # Given do i = 1 to 24;
128
+ # Return:
129
+ # (1..24).each do |i|
130
+ # @i = i
131
+ def translate_do(line)
132
+ parts = line.chop.split(/\s+/)
133
+ lines = []
134
+ finish = var_or_num(parts.pop)
135
+ parts.pop # skip to
136
+ start = var_or_num(parts.pop)
137
+ parts.pop # skip equals
138
+ var = parts.pop
139
+
140
+ lines << "(#{start} - 1..#{finish} - 1).each do |#{var}|"
141
+ lines << "\t#{ivarify(var)} = #{var}"
142
+ lines.join("\n")
143
+ end
144
+
145
+ # Given a variable, number literal, or operator
146
+ # return the appropriate translation
147
+ # See var_or_num for variables and numbers
148
+ # Operators are returned the same as they came in e.g.
149
+ # "+" => "+"
150
+ def var_or_num_or_op(vno)
151
+ return vno if @@op_regexp.match(vno)
152
+ var_or_num(vno)
153
+ end
154
+
155
+ # Places spaces around all operators so that
156
+ # we can split on white space and pick up the operators as tokens
157
+ def blow_out_ops(text)
158
+ text.gsub(@@op_regexp, ' \1 ')
159
+ end
160
+
161
+ # Given a line that assigns a value to something on the left hand side
162
+ # We need to do some basic translation of the line e.g.
163
+ # "inc2=inc2+5;" => "@inc2 = @inc2 + 5"
164
+ def translate_equals(line)
165
+ blow_out_ops(line.chop).split(/\s+/).map { |w| var_or_num_or_op(w) }.join(' ')
166
+ end
167
+
168
+ def translate_infile(line)
169
+ md = /lrecl\s*=\s*(\d+)/.match(line)
170
+ puts md
171
+ return "" if md.nil?
172
+ return "record_len(#{md[1]})"
173
+ end
174
+
175
+ # This method processes the SAS file and translates all relevant lines
176
+ def lines
177
+ if @lines.nil?
178
+ @lines = []
179
+ @@mode = :skip
180
+ File.open(@file_path).each_line do |l|
181
+ # Strip out all comments from each line
182
+ line = l.chomp.strip.gsub(@@comment_regexp, '')
183
+
184
+ # Once we hit a line with "input", start processing
185
+ @@mode = :process if line.match(/^input/i) || line.match(@@infile_regexp)
186
+ next if @@mode == :skip
187
+
188
+ # @; is ignorable, so make it a blank line
189
+ line.gsub!(/@;/, '')
190
+
191
+ # Skip blank lines
192
+ next if line.match(@@blank_line_regexp)
193
+
194
+ case line
195
+ when @@def_regexp
196
+ @lines << translate_def(line.downcase)
197
+ when @@array_regexp
198
+ @lines << translate_array(line.downcase)
199
+ when @@do_regexp
200
+ @lines << translate_do(line.downcase)
201
+ when @@infile_regexp
202
+ @lines << translate_infile(line.downcase)
203
+ when @@equals_regexp
204
+ @lines << translate_equals(line.downcase)
205
+ when @@label_start_regexp
206
+ # We hit the start of the labels, we can quit processing the file
207
+ break
208
+ when /^end;/
209
+ @lines << line.chop.downcase
210
+ end
211
+ end
212
+ end
213
+ @lines
214
+ end
215
+
216
+ def save(file_path)
217
+ File.open(file_path, 'w') do |f|
218
+ f.puts lines.join("\n")
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,82 @@
1
+ # Runs the code that we generate by translating a SAS file into Ruby
2
+ #
3
+ # This class uses "eval" to get it's job done, so be wary about what code
4
+ # you feed it
5
+ class Sassifier
6
+ def initialize(code)
7
+ @_code = code
8
+ end
9
+
10
+ def run
11
+ puts @_code
12
+ # eval the code, using the current class's context
13
+ # so that the code has access to the class's supporting methods
14
+ eval @_code, binding()
15
+ check_record_length
16
+ nil
17
+ end
18
+
19
+ def check_record_length
20
+ return if @record_length.nil?
21
+ last_column = @_hash.values.last
22
+ last_position = last_column[:column] + last_column[:length]
23
+ return if last_position >= @record_length
24
+ at(last_position, '_fill', (@record_length - last_position).to_s)
25
+ @_hash.values.last[:droppable] = true
26
+ end
27
+
28
+ # Hash where we store the field information
29
+ # Memoized so that we run the code to populate the hash on the
30
+ # first attempt to access the hash
31
+ def hash
32
+ if @_hash.nil?
33
+ @_hash = {}
34
+ run
35
+ end
36
+ @_hash
37
+ end
38
+
39
+ # Given a SAS-orient type string, return the data type
40
+ # '10.' => :integer
41
+ # '15.2' => :decimal
42
+ # All else seems to be string (so far)
43
+ def get_type(type_str)
44
+ return :integer if /^\d+\.$/.match(type_str)
45
+ return :decimal if /^\d+\.\d+$/.match(type_str)
46
+ return :string
47
+ end
48
+
49
+ # Given the same type string as described in get_type
50
+ # Return the length
51
+ # '10.' => 10
52
+ # '15.2' => 15
53
+ # '$char2' => 2
54
+ def get_length(type_str)
55
+ type_str.gsub(/^\D+/, '').to_i
56
+ end
57
+
58
+ # Given a column position, a set of names, and a type_str
59
+ # store information about the field for each name
60
+ def at(column, names, type_str)
61
+ length = get_length(type_str)
62
+ type = get_type(type_str)
63
+
64
+ # If we receive a set of names, then we assume that the names represent
65
+ # individual slices of a contiguous set of columns, all the same length
66
+ #
67
+ # So if we have column position of 1 and names %w(name1 name2) and a length of 2
68
+ # then name1 is column 1, length 2 and name2 is column3 length 2
69
+ if names.is_a?(Array)
70
+ names.each do |name|
71
+ at(column, name, type_str)
72
+ column += length
73
+ end
74
+ else
75
+ @_hash[names.to_sym] = {column: column, name: names, type: type, length: length, format: type_str}
76
+ end
77
+ end
78
+
79
+ def record_len(length)
80
+ @record_length = length
81
+ end
82
+ end
data/sas2yaml.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sas2yaml/metadata'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sas2yaml"
8
+ spec.version = Sas2Yaml::VERSION
9
+ spec.authors = ["Ryan Duryea"]
10
+ spec.email = ["aguynamedryan@gmail.com"]
11
+
12
+ spec.summary = Sas2Yaml::SUMMARY
13
+ spec.description = Sas2Yaml::DESCRIPTION
14
+ spec.homepage = "https://github.com/outcomesinsights/sas2yaml"
15
+
16
+ spec.licenses = ["MIT"]
17
+
18
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
19
+ # delete this section to allow pushing this gem to any host.
20
+ if spec.respond_to?(:metadata)
21
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
22
+ else
23
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ spec.bindir = "exe"
28
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.require_paths = ["lib"]
30
+
31
+ spec.add_development_dependency "bundler", "~> 1.10"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_dependency "escort", "~> 0.4.0"
34
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sas2yaml
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Duryea
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: escort
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.4.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.4.0
55
+ description: Converts a SAS Input file into a YAML file which details each column
56
+ along with its type, length, and start column.
57
+ email:
58
+ - aguynamedryan@gmail.com
59
+ executables:
60
+ - sas2yaml
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/setup
72
+ - exe/sas2yaml
73
+ - lib/sas2yaml.rb
74
+ - lib/sas2yaml/assemble_command.rb
75
+ - lib/sas2yaml/metadata.rb
76
+ - lib/sas2yaml/process_sas.rb
77
+ - lib/sas2yaml/rangifier.rb
78
+ - lib/sas2yaml/sas_processor.rb
79
+ - lib/sas2yaml/sassifier.rb
80
+ - sas2yaml.gemspec
81
+ homepage: https://github.com/outcomesinsights/sas2yaml
82
+ licenses:
83
+ - MIT
84
+ metadata:
85
+ allowed_push_host: https://rubygems.org
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.4.6
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Convert SAS Input files into YAML describing layout of the data
106
+ test_files: []
107
+ has_rdoc: