sqltorial 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: bc641ec92204199a0c354f413f381b544a4fc0f1
4
+ data.tar.gz: c42caec90a3cefc4a6c6273f99699fae636ed492
5
+ SHA512:
6
+ metadata.gz: 61f3145d3f3cbf346b9f88370bda5ab9fef7ad083340f562d4fde4ec16a2eda5cb64373f391a6162a253e8947da9bc91dd3fd173dc84ac160ba94e3364fc19cc
7
+ data.tar.gz: 01d990718cf2c72b49cec7ac9f308c8e0722beeb71125818e2f1f4abba06bc1d37f5f713a071bdfa8893de34209aec7e81ab0332a356a8cfae2094a3c0a69b0b
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ examples/.cache
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ ## Unreleased
5
+
6
+ ### Added
7
+ - Nothing.
8
+
9
+ ### Deprecated
10
+ - Nothing.
11
+
12
+ ### Removed
13
+ - Nothing.
14
+
15
+ ### Fixed
16
+ - Nothing.
17
+
18
+ ## 0.0.1 - 2015-08-21
19
+
20
+ ### Added
21
+ - The project itself
22
+
23
+ ### Deprecated
24
+ - Nothing.
25
+
26
+ ### Removed
27
+ - Nothing.
28
+
29
+ ### Fixed
30
+ - Nothing.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sqltorial.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 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,71 @@
1
+ # SQLtorial
2
+
3
+ Create your own SQL Tutorials with SQLtorial.
4
+
5
+
6
+ ## Motivation
7
+
8
+ SQLtorial is a gem I cooked up because I was frequently demonstrating how to write certain queries or how to explore data in certain databases. Generally, I wanted each example SQL statement to have a bit of explanation about how it works or what I’m looking for, followed by the query itself, followed by the results that SQL statement generated.
9
+
10
+ So I decided to write SQLtorial, a command that will process all files ending in \*.sql and generate a Markdown document with all the examples concatenated together.
11
+
12
+ The gem will process each .sql statement in the following manner:
13
+ - The first line is considered the title for the entire example
14
+ - Comments placed above a SQL query will be run through a Markdown formatter and placed as formatted text before the SQL query
15
+ - SQL queries must end with a ;
16
+ - SQL queries are run through [pgFormatter](https://github.com/darold/pgFormatter) to create a consistent presentation for queries
17
+ - Results from the query are shown in a table after the query. Only the first ten results are shown.
18
+
19
+ See the examples directory.
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ gem 'sqltorial'
27
+ ```
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install sqltorial
36
+
37
+ ## Usage
38
+
39
+ Create a directory for your SQL examples. Create at least one file ending with `.sql` and add comments and example queries as you see fit.
40
+
41
+ When you are ready to execute your examples against a database and compile the examples into a markdown file, create a configuration file following the instructions in the [sequelizer](https://github.com/outcomesinsights/sequelizer) README.
42
+
43
+ Once your sequelizer configuration is set up, run
44
+
45
+ $ bundle exec sqltorial
46
+
47
+ The `sqltorial` command will convert each `.sql` file into a markdown and concatenate the files into a single markdown file called `output.md`
48
+
49
+ ## Development
50
+
51
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
52
+
53
+ 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` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
54
+
55
+ ## Contributing
56
+
57
+ 1. Fork it ( https://github.com/outcomesinsights/sqltorial/fork )
58
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
59
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
60
+ 4. Push to the branch (`git push origin my-new-feature`)
61
+ 5. Create a new Pull Request
62
+
63
+ ## Thanks
64
+
65
+ - [Outcomes Insights, Inc.](http://outins.com)
66
+ - Many thanks for allowing me to release a portion of my work as Open Source Software!
67
+ - [knitr](http://yihui.name/knitr/)
68
+ - Thanks for the inspiration!
69
+
70
+ ## License
71
+ Released under the MIT license, Copyright (c) 2015 Outcomes Insights, Inc.
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 "sqltorial"
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
@@ -0,0 +1,15 @@
1
+ -- This is the title of the example
2
+ --
3
+ -- And here is the first query
4
+ SELECT 1 as column_header;
5
+
6
+ -- You can use [Markdown](https://daringfireball.net/projects/markdown/) to:
7
+ --
8
+ -- - Format your comments
9
+ --
10
+ -- - Highlight things in **bold**
11
+ --
12
+ -- - And make lists like this one, though the formatting is a bit odd. I'm looking into it.
13
+ --
14
+ -- And they'll appear above your next query like this query:
15
+ SELECT 'hey' as some_name_for_column;
@@ -0,0 +1,47 @@
1
+ ## Example 1: This is the title of the example
2
+
3
+
4
+
5
+ And here is the first query
6
+
7
+ **Query 1.1**
8
+
9
+ ```sql
10
+ SELECT
11
+ 1 AS column_header
12
+ ;
13
+ ```
14
+
15
+ Found 1 results.
16
+
17
+ | column_header |
18
+ | ------------------: |
19
+ | 1 |
20
+
21
+
22
+ You can use [Markdown](https://daringfireball.net/projects/markdown/) to:
23
+
24
+ - Format your comments
25
+
26
+ - Highlight things in **bold**
27
+
28
+ - And make lists like this one, though the formatting is a bit odd. I'm looking into it.
29
+
30
+ And they'll appear above your next query like this query:
31
+
32
+ **Query 1.2**
33
+
34
+ ```sql
35
+ SELECT
36
+ 'hey' AS some_name_for_column
37
+ ;
38
+ ```
39
+
40
+ Found 1 results.
41
+
42
+ | some_name_for_column |
43
+ | :----------------------------- |
44
+ | hey |
45
+
46
+
47
+
data/exe/sqltorial ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "escort"
4
+ require "bundler/setup"
5
+ require "sqltorial"
6
+
7
+ Escort::App.create do |app|
8
+ app.version SQLtorial::VERSION
9
+ app.summary SQLtorial::SUMMARY
10
+ app.description SQLtorial::DESCRIPTION
11
+ app.options do |opts|
12
+ opts.opt :no_results, "Don't Include Results", short: '-n', long: '--no-results', type: :boolean, default: false
13
+ opts.opt :output, "Output File", short: '-o', long: '--output', type: :string, default: 'output.md'
14
+ opts.opt :preface, "Preface File", short: '-p', long: '--preface', type: :string, default: 'preface.md'
15
+ end
16
+ app.action do |options, arguments|
17
+ begin
18
+ SQLtorial::AssembleCommand.new(options, arguments).execute
19
+ rescue
20
+ puts $!.message
21
+ puts $!.backtrace.join("\n")
22
+ raise
23
+ end
24
+ end
25
+ end
data/lib/sqltorial.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "sqltorial/metadata"
2
+ require "sqltorial/assemble_command"
3
+ require "sqltorial/directives/all_directive"
4
+ require "sqltorial/directives/valid_column_directive"
5
+
6
+ module SQLtorial
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,40 @@
1
+ require_relative 'sql_to_example'
2
+ require 'sequelizer'
3
+ require 'facets/pathname/chdir'
4
+
5
+ module SQLtorial
6
+ class AssembleCommand < ::Escort::ActionCommand::Base
7
+ include Sequelizer
8
+ def execute
9
+ process_dir.chdir do
10
+ preface = Pathname.new(global_options[:preface]) if global_options[:preface]
11
+ File.open(global_options[:output], 'w') do |f|
12
+ f.puts preface.read if preface && preface.exist?
13
+ examples = files.map.with_index do |file, index|
14
+ Escort::Logger.output.puts "Examplizing #{file.to_s}"
15
+ SqlToExample.new(file, db, index + 1).to_str(!global_options[:no_results])
16
+ end
17
+ f.puts(examples.join("\n\n"))
18
+ end
19
+ end
20
+ end
21
+
22
+ def process_dir
23
+ @process_dir = path.directory? ? path : Pathname.pwd
24
+ end
25
+
26
+ def path
27
+ @path ||= Pathname.new(arguments.first || ".")
28
+ end
29
+
30
+ def files
31
+ path.directory? ? Pathname.glob('*.sql') : files_from_file
32
+ end
33
+
34
+ def files_from_file
35
+ path.readlines.map(&:chomp!).select { |l| l !~ /^\s*#/ && !l.empty? }.map do |file_name|
36
+ Pathname.new(file_name)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "directive"
2
+
3
+ module SQLtorial
4
+ class AllDirective
5
+ REGEXP = /^ DIRECTIVE:\s*ALL/
6
+ class << self
7
+ def regexp
8
+ REGEXP
9
+ end
10
+ end
11
+
12
+ def initialize(line)
13
+ end
14
+
15
+ def alter(query_to_md)
16
+ query_to_md.row_limit = nil
17
+ end
18
+
19
+ def inspect
20
+ "ALL"
21
+ end
22
+ end
23
+ Directive.register(AllDirective)
24
+ end
25
+
26
+
@@ -0,0 +1,22 @@
1
+ module SQLtorial
2
+ class Directive
3
+ class << self
4
+ def register(directive_klass)
5
+ (@@directives ||= []) << directive_klass
6
+ end
7
+
8
+ def match(line)
9
+ @@directives.any? do |directive_klass|
10
+ directive_klass.regexp.match(line)
11
+ end
12
+ end
13
+
14
+ def from_line(line)
15
+ @@directives.each do |directive_klass|
16
+ return directive_klass.new(line) if directive_klass.regexp.match(line)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,22 @@
1
+ module SQLtorial
2
+ class ValidColumnDirective
3
+ REGEXP = /^ DIRECTIVE:\s*(\S+)\s+(\S+)\s+(.+)/
4
+ attr :column, :op, :matcher
5
+ def initialize(line)
6
+ _, column, op, matcher = REGEXP.match(line).to_a
7
+ @column = column.to_sym
8
+ @op = op
9
+ @matcher = Regexp.new(matcher)
10
+ end
11
+
12
+ def validate(result)
13
+ md = matcher.match(result[column])
14
+ op == '=' ? !md.nil? : md.nil?
15
+ end
16
+
17
+ def inspect
18
+ [column, op, matcher].join(" ")
19
+ end
20
+ end
21
+ Directive.register(AllDirective)
22
+ end
@@ -0,0 +1,6 @@
1
+ module SQLtorial
2
+ VERSION = "0.0.1"
3
+ SUMMARY = %q{Knitr, but for SQL files, sorta}
4
+ DESCRIPTION = %q{Ingests a set of commented SQL statements, executes them, and dumps the comments, queries, and results into a markdown file}
5
+ HOMEPAGE = "http://github.com/outcomesinsights/sqltorial"
6
+ end
@@ -0,0 +1,35 @@
1
+ module SQLtorial
2
+ class QueryCache
3
+ attr_reader :query_to_md
4
+
5
+ def initialize(query_to_md)
6
+ @query_to_md = query_to_md
7
+ end
8
+
9
+ def to_md
10
+ unless cache_file.exist?
11
+ make_cache_file
12
+ end
13
+ cache_file.read
14
+ end
15
+
16
+ def make_cache_file
17
+ cache_file.dirname.mkpath
18
+ cache_file.write(query_to_md.get_md)
19
+ end
20
+
21
+ def cache_file
22
+ @cache_file ||= Pathname.pwd + '.cache' + cache_file_name
23
+ end
24
+
25
+ def cache_file_name
26
+ @cache_file_name ||= Digest::SHA256.hexdigest("#{input_str}") + ".md"
27
+ end
28
+
29
+ def input_str
30
+ @input_str ||= %w(query row_limit validation_directives other_directives).inject("") do |s, meth|
31
+ s + query_to_md.send(meth).inspect
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,142 @@
1
+ require_relative 'query_cache'
2
+
3
+ module SQLtorial
4
+ class QueryToMD
5
+ attr :validation_directives, :other_directives
6
+ attr_accessor :query, :row_limit
7
+ def initialize(query, directives, row_limit = 10)
8
+ @query = query
9
+ @validation_directives, @other_directives = directives.partition { |d| d.respond_to?(:validate) }
10
+ @row_limit = row_limit
11
+ @other_directives.each do |directive|
12
+ directive.alter(self)
13
+ end
14
+ end
15
+
16
+ def row_limit
17
+ @row_limit ||= count
18
+ end
19
+
20
+ def to_md
21
+ cache.to_md
22
+ end
23
+
24
+ def get_md
25
+ return "**No results found.**" if all.empty?
26
+ output = []
27
+ output << "Found #{count} results."
28
+ if count > row_limit
29
+ output.last << " Displaying first #{row_limit}."
30
+ end
31
+ output << ""
32
+ output << tableize(all.first.keys + additional_headers)
33
+ output << tableize(orientations_for(all))
34
+ output_rows.each do |row|
35
+ output << tableize(process(row.values))
36
+ end
37
+ output.join("\n") + "\n\n"
38
+ end
39
+
40
+ def count
41
+ @count ||= query.from_self.count
42
+ end
43
+
44
+ def all
45
+ @all ||= begin
46
+ q = query.from_self
47
+ q = q.limit(row_limit)
48
+ q.all
49
+ end
50
+ end
51
+
52
+ def additional_headers
53
+ validation_directives.empty? ? [] : [:valid_row]
54
+ end
55
+
56
+ def output_rows
57
+ rows = all[0...row_limit]
58
+ return rows if validation_directives.empty?
59
+
60
+ rows.map do |row|
61
+ row[:valid_row] = validation_directives.all? { |d| d.validate(row) } ? 'Y' : 'N'
62
+ row
63
+ end
64
+ end
65
+
66
+ def tableize(columns)
67
+ "| #{columns.join(" | ")} |"
68
+ end
69
+
70
+ def processors
71
+ @processors ||= make_processors
72
+ end
73
+
74
+ def process(columns)
75
+ processors.map.with_index do |processor, index|
76
+ value = columns[index]
77
+ if processor
78
+ processor.call(value)
79
+ else
80
+ value
81
+ end
82
+ end
83
+ end
84
+
85
+ def make_processors
86
+ output_rows.first.map do |name, column|
87
+ if name.to_s.end_with?('_id')
88
+ Proc.new do |column|
89
+ column.to_s.chomp
90
+ end
91
+ else
92
+ case column
93
+ when Float, BigDecimal
94
+ Proc.new do |column|
95
+ sprintf("%.02f", column)
96
+ end
97
+ when Numeric, Fixnum
98
+ Proc.new do |column|
99
+ commatize(column.to_s)
100
+ end
101
+ else
102
+ Proc.new do |column|
103
+ column.to_s.chomp
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def orientations_for(dataset)
111
+ widths = widths_for(dataset)
112
+ dataset.first.map.with_index do |(_, value), index|
113
+ case value
114
+ when Numeric, Fixnum, Float
115
+ widths[index][-1] = ":"
116
+ else
117
+ widths[index][0] = ":"
118
+ end
119
+ widths[index]
120
+ end
121
+ end
122
+
123
+ def widths_for(dataset)
124
+ widths = [0] * dataset.first.length
125
+ dataset.each do |row|
126
+ widths = row.map.with_index do |value, index|
127
+ [value.to_s.length, widths[index]].max
128
+ end
129
+ end
130
+ widths.map { |width| '-' * width }
131
+ end
132
+
133
+ def commatize(str)
134
+ return str unless str =~ /^\d+$/
135
+ str.reverse.chars.each_slice(3).map(&:join).join(',').reverse
136
+ end
137
+
138
+ def cache
139
+ @cache ||= QueryCache.new(self)
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,31 @@
1
+ require_relative "directive"
2
+
3
+ module SQLtorial
4
+ class RegexpDirective
5
+ REGEXP = /^ DIRECTIVE:\s*(\S+)\s+(\S+)\s+(.+)/
6
+ class << self
7
+ def regexp
8
+ REGEXP
9
+ end
10
+ end
11
+
12
+ attr :column, :op, :matcher
13
+ def initialize(line)
14
+ _, column, op, matcher = REGEXP.match(line).to_a
15
+ @column = column.to_sym
16
+ @op = op
17
+ @matcher = Regexp.new(matcher)
18
+ end
19
+
20
+ def validate(result)
21
+ md = matcher.match(result[column])
22
+ op == '=' ? !md.nil? : md.nil?
23
+ end
24
+
25
+ def inspect
26
+ [column, op, matcher].join(" ")
27
+ end
28
+ end
29
+
30
+ Directive.register(RegexpDirective)
31
+ end
@@ -0,0 +1,138 @@
1
+ require 'sqltorial'
2
+ require_relative 'query_to_md'
3
+ require_relative 'formatter'
4
+
5
+ module SQLtorial
6
+ class SqlToExample
7
+ attr :file, :db
8
+ def initialize(file, db, number)
9
+ @file = file
10
+ @db = db
11
+ @number = number
12
+ end
13
+
14
+ def formatted
15
+ @formatted ||= `fsqlf -i #{file}`
16
+ #@formatted ||= `pg_format #{file}`
17
+ #@formatted ||= `cat #{file} | anbt-sql-formatter`
18
+ #@formatted ||= `cat #{file} | py_format`
19
+ #@formatted ||= formatter.format(file.read)
20
+ #file.read
21
+ end
22
+
23
+ def formatter
24
+ @formatter ||= Formatter.new
25
+ end
26
+
27
+ def formatted_lines
28
+ if @formatted_lines.nil?
29
+ @title_line, @formatted_lines = get_title_and_formatted_lines
30
+ end
31
+ @formatted_lines
32
+ end
33
+
34
+ def queries
35
+ @queries ||= formatted_lines.slice_after { |l| l =~ /;$/ }
36
+ end
37
+
38
+ def title_line
39
+ if @title_line.nil?
40
+ @title_line, @formatted_lines = get_title_and_formatted_lines
41
+ end
42
+ @title_line
43
+ end
44
+
45
+ def title
46
+ @title ||= title_line.gsub(/^\s*-+\s*/, '')
47
+ end
48
+
49
+ def make_prose_directives_and_query(query)
50
+ lines = query.dup
51
+ prose_lines = []
52
+ lines.shift while lines.first.strip.empty?
53
+ prose_lines << lines.shift.sub(/^\s*-+\s*/, ' ').chomp.sub(/^ $/, "\n\n") while lines.first =~ /^\s*(-+|$)/
54
+ directives, prose_lines = prose_lines.partition { |line| Directive.match(line) }
55
+ [prose_lines.join(''), process_directives(directives), lines.join("\n")]
56
+ end
57
+
58
+ def number
59
+ @number ||= file.basename.to_s.to_i
60
+ end
61
+
62
+ def to_str(include_results = true)
63
+ hash = {}
64
+ queries.each_with_index do |query, index|
65
+ prose, directives, sql = make_prose_directives_and_query(query)
66
+
67
+ begin
68
+ if is_create(sql)
69
+ execute(sql, include_results)
70
+ hash[sql] = [prose, create_to_md(include_results, sql, directives)];
71
+ next
72
+ elsif is_drop(sql)
73
+ execute(sql, include_results)
74
+ hash[sql] = [prose, nil];
75
+ next
76
+ end
77
+ hash[sql] = [prose, query_to_md(include_results, sql, directives)]
78
+ rescue
79
+ puts sql
80
+ puts $!.message
81
+ puts $!.backtrace.join("\n")
82
+ $stdin.gets
83
+ end
84
+ end
85
+ parts = []
86
+ parts << "## Example #{number}: #{title}\n"
87
+ part_num = 0
88
+ parts += hash.map do |key, value|
89
+ arr = [value.first]
90
+ if key && !key.empty?
91
+ part_num += 1
92
+ arr << "**Query #{number}.#{part_num}**"
93
+ arr << "```sql\n#{key}\n```"
94
+ end
95
+ arr << value.last
96
+ arr.join("\n\n")
97
+ end
98
+ parts.join("\n") + "\n\n"
99
+ end
100
+
101
+ private
102
+ def process_directives(directives)
103
+ directives.map do |line|
104
+ Directive.from_line(line)
105
+ end
106
+ end
107
+
108
+ def get_title_and_formatted_lines
109
+ all_lines = formatted.split("\n")
110
+ title_line = all_lines.shift
111
+ [title_line, all_lines]
112
+ end
113
+
114
+ def is_create(sql)
115
+ sql =~ /^\s*create/i
116
+ end
117
+
118
+ def is_drop(sql)
119
+ sql =~ /^\s*drop/i
120
+ end
121
+
122
+ def execute(sql, include_results)
123
+ db.execute(sql) if include_results
124
+ end
125
+
126
+ def create_to_md(include_results, sql, directives)
127
+ return nil unless include_results
128
+ table_name = /create\s*(?:temp)?\s*(?:table|view)\s*(\S+)/i.match(sql)[1].gsub('.', '__')
129
+ QueryToMD.new(db[table_name.to_sym], directives).to_md
130
+ end
131
+
132
+ def query_to_md(include_results, sql, directives)
133
+ return nil unless include_results
134
+ return nil if sql.empty?
135
+ QueryToMD.new(db[sql.sub(';', '')], directives).to_md
136
+ end
137
+ end
138
+ end
data/sqltorial.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sqltorial/metadata'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sqltorial"
8
+ spec.version = SQLtorial::VERSION
9
+ spec.authors = ["Ryan Duryea"]
10
+ spec.email = ["aguynamedryan@gmail.com"]
11
+
12
+ spec.summary = SQLtorial::SUMMARY
13
+ spec.description = SQLtorial::DESCRIPTION
14
+ spec.homepage = SQLtorial::HOMEPAGE
15
+ spec.license = 'MIT'
16
+
17
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
+ # delete this section to allow pushing this gem to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.9"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_dependency "sequelizer", "~> 0.0.6"
33
+ spec.add_dependency "anbt-sql-formatter", "~> 0.0.3"
34
+ spec.add_dependency "facets", "~> 3.0"
35
+ spec.add_dependency "escort", "~> 0.4.0"
36
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sqltorial
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-08-21 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.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
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: sequelizer
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.0.6
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.0.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: anbt-sql-formatter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.0.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: facets
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: escort
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.4.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.4.0
97
+ description: Ingests a set of commented SQL statements, executes them, and dumps the
98
+ comments, queries, and results into a markdown file
99
+ email:
100
+ - aguynamedryan@gmail.com
101
+ executables:
102
+ - sqltorial
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - ".travis.yml"
108
+ - CHANGELOG.md
109
+ - Gemfile
110
+ - LICENSE.txt
111
+ - README.md
112
+ - Rakefile
113
+ - bin/console
114
+ - bin/setup
115
+ - examples/example_input.sql
116
+ - examples/example_output.md
117
+ - exe/sqltorial
118
+ - lib/sqltorial.rb
119
+ - lib/sqltorial/assemble_command.rb
120
+ - lib/sqltorial/directives/all_directive.rb
121
+ - lib/sqltorial/directives/directive.rb
122
+ - lib/sqltorial/directives/valid_column_directive.rb
123
+ - lib/sqltorial/metadata.rb
124
+ - lib/sqltorial/query_cache.rb
125
+ - lib/sqltorial/query_to_md.rb
126
+ - lib/sqltorial/regexp_directive.rb
127
+ - lib/sqltorial/sql_to_example.rb
128
+ - sqltorial.gemspec
129
+ homepage: http://github.com/outcomesinsights/sqltorial
130
+ licenses:
131
+ - MIT
132
+ metadata:
133
+ allowed_push_host: https://rubygems.org
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.4.6
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Knitr, but for SQL files, sorta
154
+ test_files: []
155
+ has_rdoc: