data_doc 0.0.3 → 0.1.0
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.
- data/History.txt +11 -0
- data/README.rdoc +7 -3
- data/Rakefile +1 -1
- data/lib/data_doc/cli.rb +17 -9
- data/lib/data_doc/document.rb +88 -16
- data/lib/data_doc/present.rb +106 -0
- data/lib/data_doc/store.rb +89 -0
- data/lib/data_doc.rb +1 -2
- data/test/test_data_doc_document.rb +94 -5
- data/test/test_data_doc_present.rb +18 -0
- data/test/test_data_doc_store.rb +139 -0
- data/test/test_helper.rb +24 -0
- metadata +25 -9
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
=== 0.1.0 2012-10-23
|
2
|
+
|
3
|
+
* 2 major enhancements:
|
4
|
+
* DSL for stores, including adding rows
|
5
|
+
* DSL for presenting simple tables
|
6
|
+
|
7
|
+
* 2 known issues
|
8
|
+
* ERB processing under $SAFE = 4 unavailable
|
9
|
+
* Good testing coverage, although possibly too complex
|
10
|
+
in use of nested describes and before and after
|
11
|
+
|
1
12
|
=== 0.0.3 2012-10-22
|
2
13
|
|
3
14
|
* 4 minor enhancements:
|
data/README.rdoc
CHANGED
@@ -2,9 +2,13 @@
|
|
2
2
|
|
3
3
|
* http://github.com/alilee/data_doc
|
4
4
|
|
5
|
-
|
5
|
+
== DEVELOPMENT STATUS:
|
6
6
|
|
7
|
-
|
7
|
+
Generates html from markdown files containing erb, including layout and
|
8
|
+
headers. DSL in place for stores, attributes and simple tables. Testing
|
9
|
+
doesn't quite cover the Present DSL.
|
10
|
+
|
11
|
+
{<img src="https://secure.travis-ci.org/alilee/data_doc.png" alt="Build Status" />}[http://travis-ci.org/alilee/data_doc] {<img src="https://gemnasium.com/alilee/data_doc.png" alt="Dependency Status" />}[https://gemnasium.com/alilee/data_doc]
|
8
12
|
|
9
13
|
== DESCRIPTION:
|
10
14
|
|
@@ -58,7 +62,7 @@ your level of risk.
|
|
58
62
|
|
59
63
|
The data definition language looks like this:
|
60
64
|
|
61
|
-
connection adapter: sqlite3 database: '/tmp/example.db'
|
65
|
+
connection adapter: sqlite3 database: '/tmp/example.db' #=>
|
62
66
|
|
63
67
|
store 'priority' do
|
64
68
|
string 'name'
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ Hoe.plugin :newgem
|
|
11
11
|
$hoe = Hoe.spec 'data_doc' do
|
12
12
|
self.developer 'Alister Lee', 'gems@shortepic.com'
|
13
13
|
self.rubyforge_name = 'data-doc'
|
14
|
-
self.extra_deps = [['activerecord','
|
14
|
+
self.extra_deps = [['activerecord','~> 3.2.8'],['rdiscount','~> 1.6.8']]
|
15
15
|
end
|
16
16
|
|
17
17
|
require 'newgem/tasks'
|
data/lib/data_doc/cli.rb
CHANGED
@@ -17,7 +17,7 @@ module DataDoc
|
|
17
17
|
def self.execute(stdout, arguments=[])
|
18
18
|
|
19
19
|
doc = DataDoc::Document.new
|
20
|
-
|
20
|
+
filename = nil
|
21
21
|
|
22
22
|
OptionParser.new do |opts|
|
23
23
|
opts.banner = <<-BANNER.gsub(/^ /,'')
|
@@ -50,13 +50,8 @@ module DataDoc
|
|
50
50
|
end
|
51
51
|
|
52
52
|
opts.on("-o", "--output FILENAME",
|
53
|
-
"Put generated output in FILENAME") do |
|
54
|
-
|
55
|
-
doc.output = File.open(filename, 'w+')
|
56
|
-
rescue Exception => e
|
57
|
-
stdout.puts "ERROR with output file (#{e.message})"
|
58
|
-
return 1
|
59
|
-
end
|
53
|
+
"Put generated output in FILENAME") do |f|
|
54
|
+
filename = f
|
60
55
|
end
|
61
56
|
|
62
57
|
type_list = DataDoc::Document::OUTPUT_TYPES.join(', ')
|
@@ -97,7 +92,20 @@ module DataDoc
|
|
97
92
|
return 1
|
98
93
|
end
|
99
94
|
|
100
|
-
doc.generate(content)
|
95
|
+
result = doc.generate(content)
|
96
|
+
unless filename.nil?
|
97
|
+
begin
|
98
|
+
File.open(filename, 'w+') do |f|
|
99
|
+
f.write(result)
|
100
|
+
end
|
101
|
+
rescue Exception => e
|
102
|
+
stdout.puts "ERROR with output file (#{e.message})"
|
103
|
+
return 1
|
104
|
+
end
|
105
|
+
else
|
106
|
+
stdout.write(result)
|
107
|
+
end
|
108
|
+
0
|
101
109
|
end
|
102
110
|
end
|
103
111
|
end
|
data/lib/data_doc/document.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'rdiscount'
|
2
2
|
require 'erb'
|
3
|
+
require 'data_doc/store.rb'
|
4
|
+
require 'data_doc/present.rb'
|
3
5
|
|
4
6
|
module DataDoc
|
5
7
|
|
@@ -21,7 +23,6 @@ module DataDoc
|
|
21
23
|
#
|
22
24
|
def initialize
|
23
25
|
@format = 'html'
|
24
|
-
@output = STDOUT
|
25
26
|
@verbose = false
|
26
27
|
@read_only = false
|
27
28
|
@data_only = false
|
@@ -29,6 +30,7 @@ module DataDoc
|
|
29
30
|
@layout_filename = nil
|
30
31
|
|
31
32
|
@headers = Array.new
|
33
|
+
@stores = Hash.new
|
32
34
|
end
|
33
35
|
|
34
36
|
# MIME-type for output
|
@@ -37,23 +39,33 @@ module DataDoc
|
|
37
39
|
# Available mime types that can be generated.
|
38
40
|
OUTPUT_TYPES = ['html']
|
39
41
|
|
40
|
-
# output filename
|
41
|
-
attr_accessor :output
|
42
|
-
|
43
42
|
# display verbose output during processing
|
44
43
|
attr_accessor :verbose
|
45
44
|
|
46
45
|
# do not change schema or data
|
47
|
-
|
46
|
+
attr_reader :read_only
|
48
47
|
|
49
48
|
# do not change schema; truncates tables
|
50
49
|
attr_accessor :data_only
|
51
50
|
|
51
|
+
# ActiveRecord connection
|
52
|
+
attr_reader :connection
|
53
|
+
|
54
|
+
#
|
55
|
+
# Do not change schema or data.
|
56
|
+
#
|
57
|
+
def read_only=(ro)
|
58
|
+
@read_only = ro
|
59
|
+
@data_only = ro if ro
|
60
|
+
end
|
61
|
+
|
52
62
|
#
|
53
63
|
# Sets the database connection that the stores will be using
|
54
64
|
#
|
55
|
-
def connection=(
|
56
|
-
|
65
|
+
def connection=(conn_filename)
|
66
|
+
settings = YAML::load_file(conn_filename)
|
67
|
+
set_connection(settings)
|
68
|
+
end
|
57
69
|
|
58
70
|
#
|
59
71
|
# Sets the layout file option.
|
@@ -74,24 +86,29 @@ module DataDoc
|
|
74
86
|
def generate(content_io)
|
75
87
|
erb_content = content_io.read
|
76
88
|
begin
|
77
|
-
|
78
|
-
|
89
|
+
# @store.taint
|
90
|
+
# self.untrust
|
91
|
+
mark_down = ERB.new(erb_content, 0).result(binding.taint) # TODO: $SAFE = 4
|
79
92
|
ensure
|
80
|
-
self.trust
|
93
|
+
# self.trust
|
94
|
+
# @store.untaint
|
81
95
|
end
|
82
96
|
content_html = RDiscount.new(mark_down).to_html
|
83
|
-
|
84
|
-
@output.write(html)
|
85
|
-
0
|
97
|
+
wrap_in_layout(content_html)
|
86
98
|
end
|
87
99
|
|
88
100
|
#
|
89
101
|
# :section: 3. DSL for layout file
|
90
102
|
#
|
103
|
+
# Each function below includes a usage example which shows how it would be
|
104
|
+
# called from within a content file.
|
105
|
+
#
|
91
106
|
|
92
107
|
#
|
93
108
|
# Set layout file (from the filename, not the template content itself)
|
94
109
|
#
|
110
|
+
# <% set_layout_file 'myfile.html.erb' %>
|
111
|
+
#
|
95
112
|
# Content is html, with ERB placeholders to yield to add content at
|
96
113
|
# appropriate points.
|
97
114
|
#
|
@@ -114,6 +131,9 @@ module DataDoc
|
|
114
131
|
#
|
115
132
|
# :section: 4. DSL for header tags
|
116
133
|
#
|
134
|
+
# Each function below includes a usage example which shows how it would be
|
135
|
+
# called from within a content file.
|
136
|
+
#
|
117
137
|
|
118
138
|
#
|
119
139
|
# Sets the title tag and emits the title in a classed div.title.
|
@@ -144,14 +164,47 @@ module DataDoc
|
|
144
164
|
add_header "<link #{html_attrs(attrs)}>"
|
145
165
|
end
|
146
166
|
|
167
|
+
|
168
|
+
#
|
169
|
+
# :section: 5. DSL for stores
|
170
|
+
#
|
171
|
+
|
172
|
+
#
|
173
|
+
# Specifies ActiveRecord connection settings.
|
174
|
+
#
|
175
|
+
def set_connection(settings)
|
176
|
+
ActiveRecord::Base.establish_connection(settings)
|
177
|
+
@connection = ActiveRecord::Base.connection
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# Define a table store.
|
147
182
|
#
|
148
|
-
|
183
|
+
def store(name, opts = {}, &blk)
|
184
|
+
@stores[name.to_s] = DataDoc::Store.new(self, name, opts, &blk)
|
185
|
+
name
|
186
|
+
end
|
187
|
+
|
188
|
+
#
|
189
|
+
# :section: 6. DSL for presenting tables
|
149
190
|
#
|
150
191
|
|
192
|
+
#
|
193
|
+
# Present a table. Pass a block to set options for display.
|
194
|
+
# For more information see DataDoc::Present
|
195
|
+
#
|
196
|
+
def present(arel_or_str)
|
197
|
+
DataDoc::Present.present(self, arel_or_str)
|
198
|
+
end
|
199
|
+
|
151
200
|
protected
|
152
|
-
|
201
|
+
|
153
202
|
#
|
154
|
-
#
|
203
|
+
# :section: 9. Protected
|
204
|
+
#
|
205
|
+
|
206
|
+
#
|
207
|
+
# Isolates ERB for layout.
|
155
208
|
#
|
156
209
|
class IsolatedLayoutContext
|
157
210
|
# captures binding including any block
|
@@ -193,6 +246,25 @@ module DataDoc
|
|
193
246
|
h
|
194
247
|
end
|
195
248
|
|
249
|
+
#
|
250
|
+
# Allow use of relation names as calls for adding or querying.
|
251
|
+
#
|
252
|
+
# If no args then returns an arel for querying, otherwise assumes add.
|
253
|
+
#
|
254
|
+
def method_missing(name, *args, &block)
|
255
|
+
table_name = name.to_s
|
256
|
+
if @stores.has_key?(table_name)
|
257
|
+
if args.empty?
|
258
|
+
return @stores[table_name].arel
|
259
|
+
else
|
260
|
+
@stores[table_name].insert(*args) unless @read_only
|
261
|
+
end
|
262
|
+
else
|
263
|
+
super
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
|
196
268
|
end
|
197
269
|
|
198
270
|
end
|
data/lib/data_doc/present.rb
CHANGED
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'builder'
|
2
|
+
|
3
|
+
module DataDoc
|
4
|
+
|
5
|
+
#
|
6
|
+
# Presents the results of a query in an html table.
|
7
|
+
#
|
8
|
+
class Present
|
9
|
+
|
10
|
+
#
|
11
|
+
# Accept display options from a block. Returns html table.
|
12
|
+
#
|
13
|
+
def self.present(doc, arel_or_str, &blk)
|
14
|
+
rows = doc.connection.select_all(arel_or_str)
|
15
|
+
p = Present.new(doc, rows)
|
16
|
+
p.instance_eval(&blk) if block_given?
|
17
|
+
p.render
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Defines presentation set and order of columns.
|
22
|
+
#
|
23
|
+
# Not every field queried needs to be presented.
|
24
|
+
#
|
25
|
+
def column_order(*order)
|
26
|
+
@column_order = order
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Set the caption for the table
|
31
|
+
#
|
32
|
+
def caption(text)
|
33
|
+
@caption = text
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Rename the column heading text for a particular column.
|
38
|
+
#
|
39
|
+
def label(column, text)
|
40
|
+
@labels[column] = text
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Define a block which is called to override the contents of
|
45
|
+
# a cell.
|
46
|
+
#
|
47
|
+
# Return nil to revert to the default behaviour.
|
48
|
+
#
|
49
|
+
def each_cell(&blk) # :yields: col, row
|
50
|
+
@each_cell = blk
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Define a calculated column based on a block.
|
55
|
+
#
|
56
|
+
def calculate(col, &blk) # :yields: row
|
57
|
+
@calculated[col] = blk
|
58
|
+
end
|
59
|
+
|
60
|
+
#
|
61
|
+
# Generate html.
|
62
|
+
#
|
63
|
+
def render
|
64
|
+
h = Builder::XmlMarkup.new
|
65
|
+
h.table {
|
66
|
+
h.caption(@caption) unless @caption.nil?
|
67
|
+
h.thead {
|
68
|
+
h.tr {
|
69
|
+
@column_order.each { |c| h.th(@labels[c] || c.to_s.humanize) }
|
70
|
+
}
|
71
|
+
}
|
72
|
+
h.tfoot
|
73
|
+
h.tbody {
|
74
|
+
@rows.each do |r|
|
75
|
+
h.tr {
|
76
|
+
if @each_cell.nil?
|
77
|
+
@column_order.each {|col| h.td(r[col.to_s]) }
|
78
|
+
else
|
79
|
+
@column_order.each do |col|
|
80
|
+
h.td(@each_cell.call(r, col) || r[col.to_s])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
}
|
84
|
+
end
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
#
|
92
|
+
# Create new.
|
93
|
+
#
|
94
|
+
def initialize(doc, rows)
|
95
|
+
@doc = doc
|
96
|
+
@rows = rows
|
97
|
+
@caption = nil
|
98
|
+
@each_cell = nil
|
99
|
+
@labels = Hash.new
|
100
|
+
@calculated = Hash.new
|
101
|
+
@column_order = rows.first.keys
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
data/lib/data_doc/store.rb
CHANGED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
module DataDoc
|
4
|
+
|
5
|
+
#
|
6
|
+
# Defines schema for structured content and accepts rows.
|
7
|
+
#
|
8
|
+
# Sets up an ActiveRecord store, defines its tables and
|
9
|
+
# fields, and adds row content.
|
10
|
+
#
|
11
|
+
class Store
|
12
|
+
|
13
|
+
#
|
14
|
+
# Define a store.
|
15
|
+
#
|
16
|
+
# Yields to a block calling the store for fields and other
|
17
|
+
# schema definition. Table is re-created and emptied unless
|
18
|
+
# read_only, and just emptied if data_only.
|
19
|
+
#
|
20
|
+
def initialize(doc, table_name_or_sym, opts = {}, &blk)
|
21
|
+
@doc = doc
|
22
|
+
@connection = @doc.connection
|
23
|
+
create_store(table_name_or_sym, opts, &blk)
|
24
|
+
end
|
25
|
+
|
26
|
+
# AREL object encapsulating table.
|
27
|
+
attr_reader :arel
|
28
|
+
|
29
|
+
#
|
30
|
+
# Define a string field.
|
31
|
+
#
|
32
|
+
def string(name, opts = {})
|
33
|
+
@connection.add_column(@arel.name, name, :string, opts)
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Define an integer field.
|
38
|
+
#
|
39
|
+
def integer(name, opts = {})
|
40
|
+
@connection.add_column(@arel.name, name, :integer, opts)
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Define a text field.
|
45
|
+
#
|
46
|
+
def text(name, opts = {})
|
47
|
+
@connection.add_column(@arel.name, name, :text, opts)
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Define a datetime field.
|
52
|
+
#
|
53
|
+
def datetime(name, opts = {})
|
54
|
+
@connection.add_column(@arel.name, name, :datetime, opts)
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Insert a row from a hash.
|
59
|
+
#
|
60
|
+
def insert(record)
|
61
|
+
return if @doc.read_only
|
62
|
+
manager = @arel.insert_manager
|
63
|
+
columns = record.keys.map { |k| @arel[k] }
|
64
|
+
manager.insert(columns.zip(record.values))
|
65
|
+
@connection.insert(manager)
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
#
|
71
|
+
# Create and empty the store unless options prevent.
|
72
|
+
#
|
73
|
+
def create_store(table_name_or_sym, opts = {}, &blk)
|
74
|
+
table_name = table_name_or_sym.to_s
|
75
|
+
@arel = Arel::Table.new(table_name)
|
76
|
+
unless @doc.read_only
|
77
|
+
if @doc.data_only
|
78
|
+
@connection.delete_sql("DELETE from #{table_name}")
|
79
|
+
else
|
80
|
+
@connection.create_table(table_name, opts.merge(force: true))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
self.instance_eval(&blk) if block_given?
|
84
|
+
table_name_or_sym
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
data/lib/data_doc.rb
CHANGED
@@ -6,11 +6,10 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
6
6
|
#
|
7
7
|
module DataDoc
|
8
8
|
# Gem version
|
9
|
-
VERSION = '0.0
|
9
|
+
VERSION = '0.1.0'
|
10
10
|
# A summary of purpose of the tool.
|
11
11
|
DESCRIPTION = 'Processes structured data embedded in a markdown document and then renders it into configurable tables.'
|
12
12
|
end
|
13
13
|
|
14
14
|
require 'data_doc/document.rb'
|
15
|
-
# require 'data_doc/store.rb'
|
16
15
|
# require 'data_doc/table.rb'
|
@@ -6,14 +6,15 @@ describe DataDoc::Document do
|
|
6
6
|
@doc = DataDoc::Document.new
|
7
7
|
@input = ""
|
8
8
|
@expected_output = ""
|
9
|
+
@expected_rows = nil
|
9
10
|
end
|
10
11
|
|
11
12
|
after do
|
12
|
-
output = StringIO.new
|
13
|
-
@
|
14
|
-
@
|
15
|
-
|
16
|
-
|
13
|
+
output = @doc.generate(StringIO.new(@input))
|
14
|
+
output.strip.must_equal @expected_output.strip
|
15
|
+
unless @expected_rows.nil?
|
16
|
+
@doc.connection.select_value("select count(1) from #{@expected_table_name}").must_equal(@expected_rows)
|
17
|
+
end
|
17
18
|
end
|
18
19
|
|
19
20
|
it "should process empty input" do
|
@@ -72,5 +73,93 @@ describe DataDoc::Document do
|
|
72
73
|
end
|
73
74
|
|
74
75
|
end
|
76
|
+
|
77
|
+
describe "defining stores" do
|
78
|
+
|
79
|
+
before do
|
80
|
+
@db_filename = temp_file("")
|
81
|
+
@conn_filename = temp_file("adapter: sqlite3\ndatabase: #{@db_filename}") # YAML
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should specify connection settings to a database via DSL" do
|
85
|
+
@input = "<% set_connection adapter: 'sqlite3', database: '#{@db_filename}' %>"
|
86
|
+
@doc.layout = temp_file('')
|
87
|
+
@expected_output = ''
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should accept connection settings via option" do
|
91
|
+
@doc.connection = @conn_filename
|
92
|
+
@doc.layout = temp_file('<%= yield %>')
|
93
|
+
@input = ''
|
94
|
+
@expected_output = ''
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should define stores" do
|
98
|
+
@doc.connection = @conn_filename
|
99
|
+
@doc.layout = temp_file('<%= yield %>')
|
100
|
+
@input = "<% store 'relation' %>"
|
101
|
+
@expected_output = ''
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "adding rows" do
|
105
|
+
|
106
|
+
before do
|
107
|
+
@doc.connection = @conn_filename
|
108
|
+
@doc.layout = temp_file('<%= yield %>')
|
109
|
+
@expected_output = ''
|
110
|
+
@expected_table_name = 'relation'
|
111
|
+
@input = <<EOS
|
112
|
+
<% store 'relation' do
|
113
|
+
string 'string'
|
114
|
+
end
|
115
|
+
relation string: 'a string'
|
116
|
+
%>
|
117
|
+
EOS
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should accept a row" do
|
121
|
+
@expected_rows = 1
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "when read_only" do
|
125
|
+
|
126
|
+
before do
|
127
|
+
@doc.connection.execute("create table relation(integer id, varchar string)")
|
128
|
+
@doc.read_only = true
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should ignore a row" do
|
132
|
+
@expected_rows = 0
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "presenting tables" do
|
142
|
+
|
143
|
+
before do
|
144
|
+
db_filename = temp_file("")
|
145
|
+
conn_filename = temp_file("adapter: sqlite3\ndatabase: #{db_filename}") # YAML
|
146
|
+
@doc.connection = conn_filename
|
147
|
+
@doc.layout = temp_file('<%= yield %>')
|
148
|
+
@doc.store 'relation' do
|
149
|
+
string 'string'
|
150
|
+
integer 'number'
|
151
|
+
end
|
152
|
+
@doc.relation(string: 'a string', number: 42)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should present raw sql" do
|
156
|
+
@doc.present("select * from relation").must_match(/<table>.*<\/table>/)
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should present an arel" do
|
160
|
+
@doc.present(@doc.relation.project('*')).must_match(/<table>.*<\/table>/)
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
75
164
|
|
76
165
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'test_helper.rb'
|
2
|
+
|
3
|
+
describe DataDoc::Present do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@mock_doc = MockDoc.new
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be" do
|
10
|
+
DataDoc::Present.present(@mock_doc, "select 1")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should generate a table" do
|
14
|
+
DataDoc::Present.present(@mock_doc, "select 1").must_match(/<table>.*<\/table>/)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
data/test/test_data_doc_store.rb
CHANGED
@@ -0,0 +1,139 @@
|
|
1
|
+
require_relative 'test_helper.rb'
|
2
|
+
|
3
|
+
describe DataDoc::Store do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@mock_doc = MockDoc.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "defining stores" do
|
10
|
+
|
11
|
+
describe "create table" do
|
12
|
+
|
13
|
+
before do
|
14
|
+
@mock_doc.connection.create_table('relation', force: true)
|
15
|
+
@mock_doc.connection.add_column('relation', 'string', :string, default: 'present')
|
16
|
+
@mock_doc.connection.insert_sql('INSERT INTO relation(id) VALUES (1)')
|
17
|
+
@confirm_old_table_value = false
|
18
|
+
@confirm_old_table_column = false
|
19
|
+
end
|
20
|
+
|
21
|
+
after do
|
22
|
+
DataDoc::Store.new(@mock_doc, 'relation')
|
23
|
+
@mock_doc.connection.select_value('select count(1) from relation').must_equal @expected_rows
|
24
|
+
if @confirm_old_table_value
|
25
|
+
@mock_doc.connection.select_value('select string from relation limit 1').must_equal 'present'
|
26
|
+
end
|
27
|
+
if @confirm_old_table_column
|
28
|
+
@mock_doc.connection.insert_sql("INSERT INTO relation(string) VALUES ('hello')")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "shouldn't create a table if read_only" do
|
33
|
+
@mock_doc.read_only = true
|
34
|
+
@expected_rows = 1
|
35
|
+
@confirm_old_table_value = true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "shouldn't create a table if data_only" do
|
39
|
+
@mock_doc.data_only = true
|
40
|
+
@expected_rows = 0
|
41
|
+
@confirm_old_table_column = true
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should truncate the table if data_only" do
|
45
|
+
@mock_doc.data_only = true
|
46
|
+
@expected_rows = 0
|
47
|
+
end
|
48
|
+
|
49
|
+
it "shouldn't truncate the table if read_only" do
|
50
|
+
@mock_doc.read_only = true
|
51
|
+
@expected_rows = 1
|
52
|
+
@confirm_old_table_value = true
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "add attributes" do
|
58
|
+
|
59
|
+
def check_insert(field, value)
|
60
|
+
@mock_doc.connection.select_value("insert into relation(#{field}) values ('#{value}')").must_be_nil
|
61
|
+
end
|
62
|
+
|
63
|
+
it "adds a string attribute" do
|
64
|
+
DataDoc::Store.new(@mock_doc, 'relation') do
|
65
|
+
string 'string'
|
66
|
+
end
|
67
|
+
check_insert('string', 'a string')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "adds an integer attribute" do
|
71
|
+
DataDoc::Store.new(@mock_doc, 'relation') do
|
72
|
+
integer 'number'
|
73
|
+
end
|
74
|
+
check_insert('number', 42)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "adds a text attribute" do
|
78
|
+
DataDoc::Store.new(@mock_doc, 'relation') do
|
79
|
+
text 'description'
|
80
|
+
end
|
81
|
+
check_insert('description', 'a string')
|
82
|
+
end
|
83
|
+
|
84
|
+
it "adds a datetime attribute" do
|
85
|
+
DataDoc::Store.new(@mock_doc, 'relation') do
|
86
|
+
datetime 'timestamp'
|
87
|
+
end
|
88
|
+
check_insert('timestamp', '2012-10-12')
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "alternate keys" do
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "accepting rows" do
|
99
|
+
|
100
|
+
before do
|
101
|
+
@store = DataDoc::Store.new(@mock_doc, 'relation') do
|
102
|
+
string 's'
|
103
|
+
integer 'i'
|
104
|
+
text 't'
|
105
|
+
end
|
106
|
+
@mock_doc.connection.select_value("select count(1) from relation").must_equal 0
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "when not read_only" do
|
110
|
+
|
111
|
+
after do
|
112
|
+
@mock_doc.connection.select_value("select count(1) from relation").must_equal 1
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should accept a row" do
|
116
|
+
@store.insert(s: 'a string', i: 42, t: 'a string')
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "when read_only" do
|
122
|
+
|
123
|
+
before do
|
124
|
+
@mock_doc.read_only = true
|
125
|
+
end
|
126
|
+
|
127
|
+
after do
|
128
|
+
@mock_doc.connection.select_value("select count(1) from relation").must_equal 0
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should ignore a row" do
|
132
|
+
@store.insert(s: 'a string', i: 42, t: 'a string')
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -15,7 +15,31 @@ def temp_file(content)
|
|
15
15
|
f.path
|
16
16
|
end
|
17
17
|
|
18
|
+
|
18
19
|
# allows yield to call block
|
19
20
|
def erb(content)
|
20
21
|
ERB.new(content).result(binding)
|
21
22
|
end
|
23
|
+
|
24
|
+
# connection to temp database
|
25
|
+
def test_connection
|
26
|
+
settings = {
|
27
|
+
adapter: 'sqlite3',
|
28
|
+
database: temp_file("")
|
29
|
+
}
|
30
|
+
ActiveRecord::Base.establish_connection(settings)
|
31
|
+
ActiveRecord::Base.connection
|
32
|
+
end
|
33
|
+
|
34
|
+
# Test Document for Store and Present
|
35
|
+
class MockDoc
|
36
|
+
|
37
|
+
attr_accessor :data_only, :read_only, :connection
|
38
|
+
|
39
|
+
def initialize
|
40
|
+
@data_only = false
|
41
|
+
@read_only = false
|
42
|
+
@connection = test_connection
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: data_doc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,40 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 2.
|
21
|
+
version: 3.2.8
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.8
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rdiscount
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.6.8
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
28
44
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
45
|
+
version: 1.6.8
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: rdoc
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,7 +66,7 @@ dependencies:
|
|
50
66
|
requirements:
|
51
67
|
- - ! '>='
|
52
68
|
- !ruby/object:Gem::Version
|
53
|
-
version: 1.5.
|
69
|
+
version: 1.5.2
|
54
70
|
type: :development
|
55
71
|
prerelease: false
|
56
72
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,7 +74,7 @@ dependencies:
|
|
58
74
|
requirements:
|
59
75
|
- - ! '>='
|
60
76
|
- !ruby/object:Gem::Version
|
61
|
-
version: 1.5.
|
77
|
+
version: 1.5.2
|
62
78
|
- !ruby/object:Gem::Dependency
|
63
79
|
name: hoe
|
64
80
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,7 +141,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
141
|
version: '0'
|
126
142
|
segments:
|
127
143
|
- 0
|
128
|
-
hash: -
|
144
|
+
hash: -1350312980764895826
|
129
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
146
|
none: false
|
131
147
|
requirements:
|