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