1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
#!/usr/bin/env ruby
# coding: utf-8
require 'rubygems'
require 'bundler/setup'
Bundler.require(:doc)
require 'yaml'
output = "<table>\n"
output << <<-TAB.lines.map(&:strip).join
<tr>
<th>Adapter</th><th>Required gems</th>
<th style="writing-mode:tb">MRI support<sup>1</sup></th>
<th style="writing-mode:tb">JRuby support<sup>1</sup></th>
<th style="writing-mode:tb">Multi-thread safe<sup>2</sup></th>
<th style="writing-mode:tb">Multi-process safe<sup>3</sup></th>
<th style="writing-mode:tb">Atomic increment<sup>4</sup></th>
<th style="writing-mode:tb">Atomic create<sup>5</sup></th>
<th style="writing-mode:tb">Native expires<sup>6</sup></th>
<th style="writing-mode:tb">Persistent</th>
<th style="writing-mode:tb">Key Traversal</th>
<th style="writing-mode:tb">Bulk read<sup>7</sup></th>
<th style="writing-mode:tb">Bulk write<sup>8</sup></th>
<th>Description</th>
</tr>
TAB
output << "\n\n"
footnotes = {
"platform" => <<-EOF,
Indicates that the adapter is expected to work on this platform. Most adapters will at least
work on MRI, but some are curently considered unstable, in which case they are not supported
on any platform.
EOF
"multi-thread safe" => <<-EOF,
Make adapters thread-safe by using `Moneta::Lock` or by passing the option `threadsafe: true` to
`Moneta#new`. There is also `Moneta::Pool` which can be used to share a store between multiple
threads if the store is multi-process safe. I recommend to add the option `:threadsafe` to
ensure thread-safety since for example under JRuby and Rubinius even the basic datastructures
are not thread safe due to the lack of a global interpreter lock (GIL). This differs from MRI
where some adapters might appear thread safe already but only due to the GIL.
EOF
"multi-process safe" => <<-EOF,
Share a Moneta store between multiple processes using `Moneta::Shared` (See below).
EOF
"atomic increment" => <<-EOF,
If a store provides atomic increment it can be used with `Moneta::Semaphore`. You can add weak
`#increment` support using the `Moneta::WeakIncrement` proxy.
EOF
"atomic create" => <<-EOF,
If a store provides atomic creation it can be used with `Moneta::Mutex`. You can add weak
`#create` support using the `Moneta::WeakCreate` proxy.
EOF
"native expires" => <<-EOF,
Add expiration support by using `Moneta::Expires` or by passing the option `expires: true` to
`Moneta#new`.
EOF
"bulk read" => <<-EOF,
This indicates that there is some performance gain when fetching
multiple values at once using `#values_at`/`#fetch_values` or `#slice`.
For instance, the `MGET` instruction in Redis, or the ability to retrieve
several rows in one query in SQL.
EOF
"bulk write" => <<-EOF
This indicates that there is some performance gain when storing multiple
key/value pairs at once using `#merge!`/`#update`.
EOF
}
YAML.parse_stream(File.read(File.join(File.dirname(File.dirname(__FILE__)), 'feature_matrix.yaml'))) do |document|
feature_group = document.to_ruby
output << %{<tr><th colspan="2">#{feature_group['group']}</th><th colspan="12"></th></tr>\n\n}
feature_group['notes'].each do |k,v|
footnotes[k] = v
end
feature_group['backends'].each do |backend|
output << '<tr>'
output << "<td>#{backend['adapter']}</td>"
output << "<td>#{backend['gems'] || '-'}</td>"
features = backend['features'] | (feature_group['features'] || [])
features += backend['platforms'] || []
%w{MRI JRuby threadsafe multiprocess increment create expires persist each_key bulk_read bulk_write}.each do |feature|
supported = if features.include? feature
"yes"
elsif backend['unknown'] && backend['unknown'].include?(feature)
"unknown"
else
"no"
end
note = if backend['notes'] && backend['notes'][feature]
"<sup>#{footnotes.keys.index(backend['notes'][feature]) + 1}</sup>"
else
''
end
mark = case supported
when "yes"
"✓"
when "no"
"✗"
when "unknown"
'?'
end
colour = case supported
when "yes"
'#5F5'
when "no"
'#F44'
when "unknown"
'#55F'
end
output << %{<td style="text-align:center;background:#{colour}">#{mark}#{note}</td>}
end
html_description = if backend['description']
Kramdown::Document.new(backend['description']).to_html.match('<p>(.*)</p>')[1]
else
''
end
output << "<td>#{html_description}</td>"
output << '</tr>'
output << "\n\n"
end
end
output << "</table>\n\n"
footnotes.each_value.each_with_index do |note, idx|
output << "#{idx+1}. #{note.lines.map(&:strip).join(" ")}\n"
end
readme = File.open('README.md', 'r+')
new_readme = readme.read.sub(/(name="backend-matrix".*?\n).*?(------)/m, "\\1\n#{output}\n\\2")
readme.rewind
readme << new_readme
readme.truncate(readme.tell)
|