sas2yaml 0.0.1

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.
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: