smql 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/smql_to_ar/condition_types.rb +66 -26
- data/lib/smql_to_ar/query_builder.rb +92 -40
- data/lib/smql_to_ar.rb +26 -12
- metadata +3 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.4
|
@@ -33,15 +33,29 @@ class SmqlToAR
|
|
33
33
|
k.split( '|').collect &:to_sym
|
34
34
|
end
|
35
35
|
|
36
|
+
def conditions &e
|
37
|
+
unless block_given?
|
38
|
+
r = Enumerator.new( self, :conditions)
|
39
|
+
s = self
|
40
|
+
r.define_singleton_method :[] do |k|
|
41
|
+
s.conditions.select {|c| c::Operator === k }
|
42
|
+
end
|
43
|
+
return r
|
44
|
+
end
|
45
|
+
constants.each do |c|
|
46
|
+
next if :Condition == c
|
47
|
+
c = const_get c
|
48
|
+
next if Condition === c
|
49
|
+
yield c
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
36
53
|
# Eine Regel parsen.
|
37
54
|
# Ex: Person, "givenname=", "Peter"
|
38
55
|
def try_parse_it model, colop, val
|
39
56
|
r = nil
|
40
57
|
#p :try_parse => { :model => model, :colop => colop, :value => val }
|
41
|
-
|
42
|
-
next if :Condition == c
|
43
|
-
c = const_get c
|
44
|
-
next if Condition === c
|
58
|
+
conditions.each do |c|
|
45
59
|
raise_unless colop =~ /^(?:\d*:)?(.*?)(\W*)$/, UnexpectedColOpError.new( model, colop, val)
|
46
60
|
col, op = $1, $2
|
47
61
|
col = split_keys( col).collect {|c| Column.new model, c }
|
@@ -81,11 +95,17 @@ class SmqlToAR
|
|
81
95
|
Expected = []
|
82
96
|
Where = nil
|
83
97
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
98
|
+
class <<self
|
99
|
+
# Versuche das Objekt zu erkennen. Operator und Expected muessen passen.
|
100
|
+
# Passt das Object, die Klasse instanzieren.
|
101
|
+
def try_parse model, cols, op, val
|
102
|
+
#p :self => name, :try_parse => op, :cols => cols, :with => self::Operator, :value => val, :expected => self::Expected, :model => model.name
|
103
|
+
new model, cols, val if self::Operator === op and self::Expected.any?( &it === val)
|
104
|
+
end
|
105
|
+
|
106
|
+
def inspect
|
107
|
+
"#{self.name}(:operator=>#{self::Operator.inspect}, :expected=>#{self::Expected.inspect}, :where=>#{self::Where.inspect})"
|
108
|
+
end
|
89
109
|
end
|
90
110
|
|
91
111
|
def initialize model, cols, val
|
@@ -97,6 +117,10 @@ class SmqlToAR
|
|
97
117
|
verify
|
98
118
|
end
|
99
119
|
|
120
|
+
def inspect
|
121
|
+
"#<#{self.class.name}:0x#{(self.object_id<<1).to_s 16} model: #{self.class.name}, cols: #{@cols.inspect}, value: #{@value.inspect}>"
|
122
|
+
end
|
123
|
+
|
100
124
|
def verify
|
101
125
|
@cols.each do |col|
|
102
126
|
verify_column col
|
@@ -118,8 +142,8 @@ class SmqlToAR
|
|
118
142
|
end
|
119
143
|
|
120
144
|
# Erstelle alle noetigen Klauseln. builder nimmt diese entgegen,
|
121
|
-
# wobei builder.
|
122
|
-
# mehrere Schluessel bedeuten, dass die Values _alle_ zutreffen muessen, wobei die Schluessel
|
145
|
+
# wobei builder.joins, builder.select, builder.where und builder.wobs von interesse sind.
|
146
|
+
# mehrere Schluessel bedeuten, dass die Values _alle_ zutreffen muessen, wobei die Schluessel geODERt werden.
|
123
147
|
# Ex:
|
124
148
|
# 1) {"givenname=", "Peter"} #=> givenname = 'Peter'
|
125
149
|
# 2) {"givenname=", ["Peter", "Hans"]} #=> ( givenname = 'Peter' OR givenname = 'Hans' )
|
@@ -132,11 +156,11 @@ class SmqlToAR
|
|
132
156
|
@cols.each do |col|
|
133
157
|
col.joins builder, table
|
134
158
|
col = builder.column table+col.path, col.col
|
135
|
-
builder.where
|
159
|
+
builder.where values.keys.collect {|vid| self.class::Where % [ col, vid.to_s ] }
|
136
160
|
end
|
137
161
|
else
|
138
162
|
values.keys.each do |vid|
|
139
|
-
builder.where
|
163
|
+
builder.where @cols.collect {|col|
|
140
164
|
col.joins builder, table
|
141
165
|
col = builder.column table+col.path, col.col
|
142
166
|
self.class::Where % [ col, vid.to_s ]
|
@@ -189,19 +213,26 @@ class SmqlToAR
|
|
189
213
|
|
190
214
|
In = simple_condition NotIn, '|=', '%s IN (%s)', [Array]
|
191
215
|
In2 = simple_condition In, '', nil, [Array]
|
192
|
-
NotEqual = simple_condition Condition,
|
216
|
+
NotEqual = simple_condition Condition, '!=', "%s <> %s", [Array, String, Numeric]
|
217
|
+
NotEqual2 = simple_condition Condition, '<>', "%s <> %s", [Array, String, Numeric]
|
193
218
|
GreaterThanOrEqual = simple_condition Condition, '>=', "%s >= %s", [Array, Numeric]
|
194
219
|
LesserThanOrEqual = simple_condition Condition, '<=', "%s <= %s", [Array, Numeric]
|
220
|
+
|
221
|
+
# Examples:
|
222
|
+
# { 'articles=>' => { id: 1 } }
|
223
|
+
# { 'articles=>' => [ { id: 1 }, { id: 2 } ] }
|
195
224
|
class EqualJoin <Condition
|
196
|
-
Operator = '
|
197
|
-
Expected = [Hash]
|
225
|
+
Operator = '=>'
|
226
|
+
Expected = [Hash, lambda {|x| x.kind_of?( Array) and x.all?( &it.kind_of?( Hash))}]
|
198
227
|
|
199
228
|
def initialize *pars
|
200
229
|
super( *pars)
|
230
|
+
@value = Array.wrap @value
|
201
231
|
cols = {}
|
232
|
+
p self: self, cols: @cols
|
202
233
|
@cols.each do |col|
|
203
234
|
col_model = col.relation
|
204
|
-
cols[col] = [col_model] + ConditionTypes.try_parse( col_model,
|
235
|
+
cols[col] = [col_model] + @value.collect {|val| ConditionTypes.try_parse( col_model, val) }
|
205
236
|
end
|
206
237
|
@cols = cols
|
207
238
|
end
|
@@ -212,11 +243,14 @@ class SmqlToAR
|
|
212
243
|
|
213
244
|
def build builder, table
|
214
245
|
@cols.each do |col, sub|
|
246
|
+
model, *sub = sub
|
215
247
|
t = table + col.path + [col.col]
|
216
|
-
col.joins.each {|j, m| builder.
|
217
|
-
builder.
|
218
|
-
sub
|
248
|
+
col.joins.each {|j, m| builder.joins table+j, m }
|
249
|
+
builder.joins t, model
|
250
|
+
b2 = 1 == sub.length ? builder : Or.new( builder)
|
251
|
+
sub.each {|i| i.collect( &it.build( And.new( b2), t)); p 'or' => b2 }
|
219
252
|
end
|
253
|
+
ap '=>' => builder
|
220
254
|
self
|
221
255
|
end
|
222
256
|
end
|
@@ -250,8 +284,7 @@ class SmqlToAR
|
|
250
284
|
def build builder, table
|
251
285
|
@cols.each do |col, sub|
|
252
286
|
t = table+col.to_a
|
253
|
-
|
254
|
-
builder.sub_join t, col, *sub[0..1]
|
287
|
+
builder.sub_joins t, col, *sub[0..1]
|
255
288
|
sub[2..-1].each &it.build( builder, t)
|
256
289
|
end
|
257
290
|
self
|
@@ -264,8 +297,9 @@ class SmqlToAR
|
|
264
297
|
LesserThan = simple_condition Condition, '<', "%s < %s", [Array, Numeric]
|
265
298
|
NotIlike = simple_condition Condition, '!~', "%s NOT ILIKE %s", [Array, String]
|
266
299
|
Ilike = simple_condition Condition, '~', "%s ILIKE %s", [Array, String]
|
300
|
+
Exists = simple_condition Condition, '', '%s IS NOT NULL', [true]
|
301
|
+
NotExists = simple_condition Condition, '', '%s IS NULL', [false]
|
267
302
|
|
268
|
-
####### No Operator #######
|
269
303
|
Join = simple_condition EqualJoin, '', nil, [Hash]
|
270
304
|
InRange2 = simple_condition InRange, '', nil, [Range]
|
271
305
|
class Select < Condition
|
@@ -300,9 +334,15 @@ class SmqlToAR
|
|
300
334
|
Expected = []
|
301
335
|
attr_reader :model, :func, :args
|
302
336
|
|
303
|
-
|
304
|
-
|
305
|
-
|
337
|
+
class <<self
|
338
|
+
def try_parse model, func, args
|
339
|
+
SmqlToAR.logger.info( { try_parse: [func,args]}.inspect)
|
340
|
+
self.new model, func, args if self::Name === func and self::Expected.any?( &it === args)
|
341
|
+
end
|
342
|
+
|
343
|
+
def inspect
|
344
|
+
"#{self.name}(:name=>#{self::Name}, :expected=>#{self::Expected})"
|
345
|
+
end
|
306
346
|
end
|
307
347
|
|
308
348
|
def initialize model, func, args
|
@@ -29,30 +29,34 @@ class SmqlToAR
|
|
29
29
|
end
|
30
30
|
|
31
31
|
attr_reader :table_alias, :model, :table_model, :base_table, :_where, :_select, :_wobs, :_joins, :prefix, :_vid
|
32
|
-
attr_accessor :logger
|
32
|
+
attr_accessor :logger, :limit, :offset
|
33
33
|
|
34
|
-
def initialize model, prefix = nil
|
34
|
+
def initialize model, prefix = nil
|
35
35
|
@prefix = "smql"
|
36
36
|
@logger = SmqlToAR.logger
|
37
37
|
@table_alias = Hash.new do |h, k|
|
38
|
-
|
39
|
-
h[k] = "#{@prefix},#{
|
38
|
+
j = Array.wrap( k).compact
|
39
|
+
h[k] = h.key?(j) ? h[j] : "#{@prefix},#{j.join(',')}"
|
40
40
|
end
|
41
|
-
@_vid, @_where, @_wobs, @model, @quoter = 0, [], {}, model, model.connection
|
42
|
-
@base_table =
|
41
|
+
@_vid, @_where, @_wobs, @model, @quoter = 0, SmqlToAR::And[], {}, model, model.connection
|
42
|
+
@base_table = [model.table_name.to_sym]
|
43
43
|
@table_alias[ @base_table] = @base_table.first
|
44
44
|
t = quote_table_name @table_alias[ @base_table]
|
45
|
-
@_select, @_joins, @_joined, @_includes, @_order = ["DISTINCT #{t}.*"], "", [], [], []
|
45
|
+
@_select, @_joins, @_joined, @_includes, @_order = ["DISTINCT #{t}.*"], "", [@base_table], [], []
|
46
46
|
@table_model = {@base_table => @model}
|
47
47
|
end
|
48
48
|
|
49
49
|
def vid() Vid.new( @_vid+=1) end
|
50
50
|
|
51
|
+
def inspect
|
52
|
+
"#<#{self.class.name}:#{"0x%x"% (self.object_id<<1)}|#{@prefix}:#{@base_table}:#{@model} vid=#{@_vid} where=#{@_where} wobs=#{@_wobs} select=#{@_select} aliases=#{@_table_alias}>"
|
53
|
+
end
|
54
|
+
|
51
55
|
# Jede via where uebergebene Condition wird geodert und alle zusammen werden geundet.
|
52
56
|
# "Konjunktive Normalform". Allerdings duerfen Conditions auch Komplexe Abfragen enthalten.
|
53
|
-
# Ex: builder.where( 'a = a', 'b = c').where( 'c = d', 'e = e').where( 'x = y').where( '( m = n AND o = p )', 'f = g')
|
57
|
+
# Ex: builder.where( ['a = a', 'b = c']).where( ['c = d', 'e = e']).where( 'x = y').where( ['( m = n AND o = p )', 'f = g'])
|
54
58
|
# #=> WHERE ( a = a OR b = c ) AND ( c = d OR e = e ) AND x = y ( ( m = n AND o = p ) OR f = g )
|
55
|
-
def where
|
59
|
+
def where cond
|
56
60
|
@_where.push cond
|
57
61
|
self
|
58
62
|
end
|
@@ -75,28 +79,24 @@ class SmqlToAR
|
|
75
79
|
end
|
76
80
|
|
77
81
|
def build_join orig, pretable, table, prekey, key
|
78
|
-
" JOIN #{orig} AS #{quote_table_name table} ON #{column pretable, prekey} = #{column table, key} "
|
82
|
+
" LEFT OUTER JOIN #{orig} AS #{quote_table_name table} ON #{column pretable, prekey} = #{column table, key} "
|
79
83
|
end
|
80
84
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
join_ table, model, "(#{query.build( prefix, base_table).tap{|q| p :sub_join => q }.ar.to_sql})"
|
85
|
+
def sub_joins table, col, model, query
|
86
|
+
prefix, base_table = "#{@prefix}_sub", col.relation.table_name
|
87
|
+
join_ table, model, "(#{query.build( prefix).ar.to_sql})"
|
85
88
|
end
|
86
89
|
|
87
90
|
def join_ table, model, query, pretable = nil
|
88
|
-
pp [:join_, table, model, query]
|
89
91
|
pretable ||= table[0...-1]
|
90
92
|
@table_model[ table] = model
|
91
93
|
premodel = @table_model[ pretable]
|
92
94
|
t = @table_alias[ table]
|
93
95
|
pt = quote_table_name @table_alias[ table[ 0...-1]]
|
94
|
-
pp premodel: premodel, table: table
|
95
96
|
refl = premodel.reflections[table.last]
|
96
97
|
case refl
|
97
98
|
when ActiveRecord::Reflection::ThroughReflection
|
98
99
|
through = refl.through_reflection
|
99
|
-
pp refl: refl
|
100
100
|
throughtable = table[0...-1]+[through.name.to_sym]
|
101
101
|
srctable = throughtable+[refl.source_reflection.name]
|
102
102
|
@table_model[ srctable] = model
|
@@ -120,7 +120,8 @@ class SmqlToAR
|
|
120
120
|
self
|
121
121
|
end
|
122
122
|
|
123
|
-
def
|
123
|
+
def joins table, model
|
124
|
+
table = table.flatten.compact
|
124
125
|
return self if @_joined.include? table # Already joined
|
125
126
|
join_ table, model, quote_table_name( model.table_name)
|
126
127
|
@_joined.push table
|
@@ -140,40 +141,22 @@ class SmqlToAR
|
|
140
141
|
@_order.push "#{column table, col} #{:DESC == o ? :DESC : :ASC}"
|
141
142
|
end
|
142
143
|
|
143
|
-
def limit count
|
144
|
-
@_limit = count
|
145
|
-
end
|
146
|
-
|
147
|
-
def offset count
|
148
|
-
@_offset = count
|
149
|
-
end
|
150
|
-
|
151
|
-
class Dummy
|
152
|
-
def method_missing m, *a, &e
|
153
|
-
#p :dummy => m, :pars => a, :block => e
|
154
|
-
self
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
144
|
def build_ar
|
159
|
-
where_str = @_where.
|
160
|
-
w = Array.wrap w
|
161
|
-
1 == w.length ? w.first : "( #{w.join( ' OR ')} )"
|
162
|
-
end.join ' AND '
|
145
|
+
where_str = @_where.type_correction!.optimize!.tap {|x| p x }.build_where
|
163
146
|
incls = {}
|
164
147
|
@_includes.each do |inc|
|
165
148
|
b = incls
|
166
149
|
inc[1..-1].collect {|rel| b = b[rel] ||= {} }
|
167
150
|
end
|
168
|
-
@logger.
|
151
|
+
@logger.info where: where_str, wobs: @_wobs
|
169
152
|
@model = @model.
|
170
153
|
select( @_select.join( ', ')).
|
171
154
|
joins( @_joins).
|
172
155
|
where( where_str, @_wobs).
|
173
156
|
order( @_order.join( ', ')).
|
174
157
|
includes( incls)
|
175
|
-
@model = @model.limit @
|
176
|
-
@model = @model.offset @
|
158
|
+
@model = @model.limit @limit if @limit
|
159
|
+
@model = @model.offset @offset if @offset
|
177
160
|
@model
|
178
161
|
end
|
179
162
|
|
@@ -193,4 +176,73 @@ class SmqlToAR
|
|
193
176
|
@model
|
194
177
|
end
|
195
178
|
end
|
179
|
+
|
180
|
+
class SubBuilder < Array
|
181
|
+
attr_reader :parent, :_where
|
182
|
+
delegate :wobs, :joins, :includes, :sub_joins, :vid, :quote_column_name, :quoter, :quote_table_name, :column, :to => :parent
|
183
|
+
|
184
|
+
def initialize parent, tmp = false
|
185
|
+
p init: self, parent: parent
|
186
|
+
@parent = parent
|
187
|
+
@parent.where self unless @parend.nil? && tmp
|
188
|
+
end
|
189
|
+
|
190
|
+
def new parent, tmp = false
|
191
|
+
super parent, tmp
|
192
|
+
#return parent if self.class == parent.class
|
193
|
+
#super parent
|
194
|
+
end
|
195
|
+
|
196
|
+
alias where push
|
197
|
+
|
198
|
+
def type_correction!
|
199
|
+
collect! do |sub|
|
200
|
+
if sub.kind_of? Array
|
201
|
+
sub = default[ *sub] unless sub.respond_to?( :type_correction!)
|
202
|
+
sub.type_correction!
|
203
|
+
end
|
204
|
+
sub
|
205
|
+
end
|
206
|
+
self
|
207
|
+
end
|
208
|
+
|
209
|
+
def optimize!
|
210
|
+
p optimize: self
|
211
|
+
ext = []
|
212
|
+
collect! do |sub|
|
213
|
+
sub = sub.optimize! if sub.kind_of? Array
|
214
|
+
if self.class == sub.class
|
215
|
+
ext.push *sub
|
216
|
+
nil
|
217
|
+
elsif sub.blank?
|
218
|
+
nil
|
219
|
+
else
|
220
|
+
sub
|
221
|
+
end
|
222
|
+
end.compact!
|
223
|
+
p optimized: self
|
224
|
+
p ext: ext
|
225
|
+
push *ext
|
226
|
+
self
|
227
|
+
end
|
228
|
+
|
229
|
+
def inspect
|
230
|
+
"#{self.class.name.sub( /.*::/, '')}[ #{collect(&:inspect).join ', '}]"
|
231
|
+
end
|
232
|
+
def default() SmqlToAR::And end
|
233
|
+
def default_new( parent) default.new self, parent, false end
|
234
|
+
end
|
235
|
+
|
236
|
+
class And < SubBuilder
|
237
|
+
def default; SmqlToAR::Or; end
|
238
|
+
def build_where
|
239
|
+
join ' AND '
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
class Or < SubBuilder
|
244
|
+
def build_where
|
245
|
+
join ' OR '
|
246
|
+
end
|
247
|
+
end
|
196
248
|
end
|
data/lib/smql_to_ar.rb
CHANGED
@@ -107,7 +107,9 @@ class SmqlToAR
|
|
107
107
|
|
108
108
|
# Model der Relation `rel` von `model`
|
109
109
|
def self.model_of model, rel
|
110
|
-
|
110
|
+
rel = rel.to_sym
|
111
|
+
r = model.reflections[ rel].andand.klass
|
112
|
+
r.nil? && :self == rel ? model : r
|
111
113
|
end
|
112
114
|
|
113
115
|
# Eine Spalte in einer Tabelle, relativ zu `Column#model`.
|
@@ -121,7 +123,7 @@ class SmqlToAR
|
|
121
123
|
def initialize model, *col
|
122
124
|
@model = model
|
123
125
|
@last_model = nil
|
124
|
-
*@path, @col = Array.wrap( col).collect( &it.to_s.split( /[.\/]/)).flatten.collect( &:to_sym)
|
126
|
+
*@path, @col = *Array.wrap( col).collect( &it.to_s.split( /[.\/]/)).flatten.collect( &:to_sym).reject( &it==:self)
|
125
127
|
end
|
126
128
|
|
127
129
|
def last_model
|
@@ -131,9 +133,12 @@ class SmqlToAR
|
|
131
133
|
def each
|
132
134
|
model = @model
|
133
135
|
@path.each do |rel|
|
134
|
-
|
135
|
-
|
136
|
-
|
136
|
+
rel = rel.to_sym
|
137
|
+
unless :self == rel
|
138
|
+
model = SmqlToAR.model_of model, rel
|
139
|
+
return false unless model
|
140
|
+
yield rel, model
|
141
|
+
end
|
137
142
|
end
|
138
143
|
model
|
139
144
|
end
|
@@ -158,20 +163,21 @@ class SmqlToAR
|
|
158
163
|
def joins builder = nil, table = nil, &exe
|
159
164
|
pp = []
|
160
165
|
table = Array.wrap table
|
161
|
-
exe ||= builder ? lambda {|j, m| builder.
|
166
|
+
exe ||= builder ? lambda {|j, m| builder.joins table+j, m} : Array.method( :[])
|
162
167
|
collect do |rel, model|
|
163
168
|
pp.push rel
|
164
169
|
exe.call pp, model
|
165
170
|
end
|
166
171
|
end
|
167
|
-
def
|
168
|
-
def
|
169
|
-
def
|
172
|
+
def self?() !@col end
|
173
|
+
def length() @path.length+(self.self? ? 0 : 1) end
|
174
|
+
def size() @path.size+(self.self? ? 0 : 1) end
|
175
|
+
def to_a() @path+(self.self? ? [] : [@col]) end
|
170
176
|
def to_s() to_a.join '.' end
|
171
177
|
def to_sym() to_s.to_sym end
|
172
178
|
def to_json() to_s end
|
173
179
|
def inspect() "#<Column: #{model} #{to_s}>" end
|
174
|
-
def relation() SmqlToAR.model_of last_model, @col end
|
180
|
+
def relation() self.self? ? model : SmqlToAR.model_of( last_model, @col) end
|
175
181
|
def allowed?() ! self.protected? end
|
176
182
|
def child?() @path.empty? and !!relation end
|
177
183
|
end
|
@@ -225,9 +231,9 @@ class SmqlToAR
|
|
225
231
|
self
|
226
232
|
end
|
227
233
|
|
228
|
-
def build prefix = nil
|
234
|
+
def build prefix = nil
|
229
235
|
benchmark 'SMQL build query' do
|
230
|
-
@builder = QueryBuilder.new @model, prefix
|
236
|
+
@builder = QueryBuilder.new @model, prefix
|
231
237
|
table = @builder.base_table
|
232
238
|
@conditions.each &it.build( builder, table)
|
233
239
|
end
|
@@ -252,4 +258,12 @@ class SmqlToAR
|
|
252
258
|
def self.to_ar *params
|
253
259
|
new( *params).to_ar
|
254
260
|
end
|
261
|
+
|
262
|
+
def self.reload_library
|
263
|
+
lib_dir = File.dirname __FILE__
|
264
|
+
fj = lambda {|*a| File.join lib_dir, *a }
|
265
|
+
load fj.call( 'smql_to_ar.rb')
|
266
|
+
load fj.call( 'smql_to_ar', 'condition_types.rb')
|
267
|
+
load fj.call( 'smql_to_ar', 'query_builder.rb')
|
268
|
+
end
|
255
269
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 4
|
9
|
+
version: 0.0.4
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Denis Knauf
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-10-05 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|