r18n-core 0.4 → 0.4.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.
data/ChangeLog CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.4.1 (Lazy Boole)
2
+ * Add passive filters.
3
+ * Receive filter position as option Hash.
4
+ * Fix base translations (by Pavel Kunc).
5
+
1
6
  == 0.4 (D-Day)
2
7
  * Rails I18n compatibility.
3
8
  * Rewrite a lot of core code to fast and cleanup version.
@@ -46,7 +51,7 @@
46
51
  * Ruby 1.9 compatibility.
47
52
  * Add German locale (by Benjamin Meichsner).
48
53
 
49
- == 0.2 (Freedom of language)
54
+ == 0.2 (Freedom of Language)
50
55
  * Locale class can be extended for special language (for example, Indian locale
51
56
  may has another digits grouping).
52
57
  * Load translations from several dirs.
data/README.rdoc CHANGED
@@ -220,12 +220,13 @@ See <tt>base/</tt> in dir in gem.
220
220
  === Filters
221
221
 
222
222
  You can also add you own filter for translations: escape HTML entries, convert
223
- from Markdown syntax, etc.
223
+ from Markdown syntax, etc. Filters can be passive to process translation only on
224
+ loading.
224
225
 
225
226
  R18n::Filters.add('custom_type', :filter_name) do |content, config, replace|
226
227
  content.gsub(' ', replace)
227
228
  end
228
- R18n::Filters.add('custom_type') do |content, config, replace|
229
+ R18n::Filters.add('custom_type', :passive => true) do |content, config|
229
230
  content + '!'
230
231
  end
231
232
 
data/base/cs.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: OK
2
2
  save: Uložit
3
3
  cancel: Zrušit
4
- yes: Ano
5
- no: Ne
4
+ 'yes': Ano
5
+ 'no': Ne
6
6
  exit: Konec
7
7
  delete: Smazat
8
8
 
data/base/de.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: OK
2
2
  save: Speichern
3
3
  cancel: Abbrechen
4
- yes: Ja
5
- no: Nein
4
+ 'yes': Ja
5
+ 'no': Nein
6
6
  exit: Ausgang
7
7
  delete: Löschen
8
8
 
@@ -28,4 +28,4 @@ human_time:
28
28
  yesterday: gestern
29
29
  days_ago: !!pl
30
30
  1: %1 Tag vor
31
- n: %1 Tagen vor
31
+ n: %1 Tagen vor
data/base/en.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: OK
2
2
  save: Save
3
3
  cancel: Cancel
4
- yes: Yes
5
- no: No
4
+ 'yes': 'Yes'
5
+ 'no': 'No'
6
6
  exit: Exit
7
7
  delete: Delete
8
8
 
data/base/eo.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: Ek
2
2
  save: Savi
3
3
  cancel: Nuligi
4
- yes: Jes
5
- no: Ne
4
+ 'yes': Jes
5
+ 'no': Ne
6
6
  exit: Eliro
7
7
  delete: Forviŝi
8
8
 
data/base/es.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: OK
2
2
  save: Guardar
3
3
  cancel: Cancelar
4
- yes: Sí
5
- no: No
4
+ 'yes': Sí
5
+ 'no': 'No'
6
6
  exit: Salir
7
7
  delete: Suprimir
8
8
 
data/base/fr.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: O.K.
2
2
  save: Enregistrer
3
3
  cancel: Annuler
4
- yes: Oui
5
- no: Non
4
+ 'yes': Oui
5
+ 'no': Non
6
6
  exit: Sortie
7
7
  delete: Supprimer
8
8
 
data/base/it.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: OK
2
2
  save: Salva
3
3
  cancel: Annulla
4
- yes: Sì
5
- no: No
4
+ 'yes': Sì
5
+ 'no': 'No'
6
6
  exit: Esci
7
7
  delete: Cancella
8
8
 
data/base/kk.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  ok: OK
2
2
  save: Сақтау
3
3
  cancel: Болдырмау
4
- yes: Иә
5
- no: Жоқ
4
+ 'yes': Иә
5
+ 'no': Жоқ
6
6
  exit: Шығу
7
7
  delete: Алыстату
data/base/pl.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: OK
2
2
  save: Zapisz
3
3
  cancel: Anuluj
4
- yes: Tak
5
- no: Nie
4
+ 'yes': Tak
5
+ 'no': Nie
6
6
  exit: Wyjście
7
7
  delete: Usuń
8
8
 
data/base/pt_br.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: OK
2
2
  save: Salvar
3
3
  cancel: Cancelar
4
- yes: Sim
5
- no: Não
4
+ 'yes': Sim
5
+ 'no': Não
6
6
  exit: Sair
7
7
  delete: Apagar
8
8
 
data/base/ru.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: OK
2
2
  save: Сохранить
3
3
  cancel: Отмена
4
- yes: Да
5
- no: Нет
4
+ 'yes': Да
5
+ 'no': Нет
6
6
  exit: Выход
7
7
  delete: Удалить
8
8
 
data/base/zh.yml CHANGED
@@ -1,8 +1,8 @@
1
1
  ok: OK
2
2
  save: 保存
3
3
  cancel: 取消
4
- yes: 是
5
- no: 否
4
+ 'yes': 是
5
+ 'no': 否
6
6
  exit: 退出
7
7
  delete: 删除
8
8
 
@@ -30,12 +30,13 @@ module R18n
30
30
  # This content will be processed by filter
31
31
  #
32
32
  # Filter function will be receive filtered content as first argument, struct
33
- # with filter config as second and filter parameters as next arguments.
33
+ # with filter config as second and filter parameters as next arguments. You
34
+ # can set passive filter, which will process translation only on loading.
34
35
  #
35
36
  # R18n::Filters.add('custom_type', :no_space) do |content, config, replace|
36
37
  # content.gsub(' ', replace)
37
38
  # end
38
- # R18n::Filters.add('custom_type') do |content, config, replace|
39
+ # R18n::Filters.add('custom_type', :passive => true) do |content, config|
39
40
  # content + '!'
40
41
  # end
41
42
  #
@@ -48,7 +49,7 @@ module R18n
48
49
  # end
49
50
  #
50
51
  # Filter config contain two parameters: translation locale and path. But it is
51
- # OpenStruct and you can add you own parameter to cross-filter communications:
52
+ # Hash and you can add you own parameter to cross-filter communications:
52
53
  #
53
54
  # R18n::Filters.add(String, :hide_truth) do |content, config|
54
55
  # return content if config[:censorship_check]
@@ -73,67 +74,82 @@ module R18n
73
74
  # i18n.filtered('_') #=> "This_content_will_be_processed_by_filter!"
74
75
  # R18n::Filters.delete(:no_space)
75
76
  module Filters
76
- Filter = Struct.new(:name, :type, :block, :enabled) do
77
- def call(*params)
78
- block.call(*params)
79
- end
80
-
81
- def enabled?
82
- enabled
83
- end
84
- end
85
-
86
77
  class << self
87
78
  # Hash of filter names to Filters.
88
- def defined
89
- @defined ||= {}
90
- end
91
-
92
- # Hash of types to enabled Filters.
93
- def enabled
94
- @enabled ||= Hash.new([])
95
- end
79
+ attr_accessor :defined
96
80
 
97
81
  # Hash of types to all Filters.
98
- def by_type
99
- @by_type ||= Hash.new([])
100
- end
82
+ attr_accessor :by_type
83
+
84
+ # Hash of types to enabled active filters.
85
+ attr_accessor :active_enabled
101
86
 
102
- # Process +value+ by global filters and filters for special +type+.
103
- def process(type, value, locale, path, params)
87
+ # Hash of types to enabled passive filters.
88
+ attr_accessor :passive_enabled
89
+
90
+ # Hash of types to enabled passive and active filters.
91
+ attr_accessor :enabled
92
+
93
+ # Process +value+ by filters in +enabled+.
94
+ def process(enabled, type, value, locale, path, params)
104
95
  config = { :locale => locale, :path => path }
105
96
 
106
- Filters.enabled[type].each { |f| value = f.call(value, config, *params)}
97
+ enabled[type].each do |filter|
98
+ value = filter.call(value, config, *params)
99
+ end
107
100
 
108
101
  if value.is_a? String
109
102
  value = TranslatedString.new(value, locale, path)
110
- process_string(value, config, params)
103
+ process_string(enabled, value, config, params)
111
104
  else
112
105
  value
113
106
  end
114
107
  end
115
108
 
116
- # Process +value+ by global filters.
117
- def process_string(value, config, params)
109
+ # Process +value+ by global filters in +enabled+.
110
+ def process_string(enabled, value, config, params)
118
111
  if config.is_a? String
119
112
  config = { :locale => value.locale, :path => config }
120
113
  end
121
- Filters.enabled[String].each do |f|
114
+ enabled[String].each do |f|
122
115
  value = f.call(value, config, *params)
123
116
  end
124
117
  value
125
118
  end
126
119
 
120
+ # Rebuild +active_enabled+ and +passive_enabled+ for +type+.
121
+ def rebuild_enabled!(type)
122
+ @passive_enabled[type] = []
123
+ @active_enabled[type] = []
124
+ @enabled[type] = []
125
+
126
+ @by_type[type].each do |filter|
127
+ if filter.enabled?
128
+ @enabled[type] << filter
129
+ if filter.passive?
130
+ @passive_enabled[type] << filter
131
+ else
132
+ @active_enabled[type] << filter
133
+ end
134
+ end
135
+ end
136
+ end
137
+
127
138
  # Add new filter for +type+ with +name+ and return filter object. You
128
139
  # can use String class as +type+ to add global filter for all translated
129
140
  # string.
130
141
  #
131
- # Several filters for same type will be call consecutively, but you can
132
- # set +position+ in call list.
133
- #
134
142
  # Filter content will be sent to +block+ as first argument, struct with
135
143
  # config as second and filters parameters will be in next arguments.
136
- def add(type, name = nil, position = nil, &block)
144
+ #
145
+ # Options:
146
+ # * +position+ – change order on processing several filters for same type.
147
+ # Note that passive filters will be always run before active.
148
+ # * +passive+ – if +true+, filter will process only on translation
149
+ # loading. Note that you must add all passive before load translation.
150
+ def add(type, name = nil, options = {}, &block)
151
+ options, name = name, nil if name.is_a? Hash
152
+
137
153
  unless name
138
154
  @last_auto_name ||= 0
139
155
  begin
@@ -144,52 +160,61 @@ module R18n
144
160
  delete(name)
145
161
  end
146
162
 
147
- filter = Filter.new(name, type, block, true)
148
- defined[name] = filter
163
+ @by_type[type] = [] unless @by_type.has_key? type
149
164
 
150
- unless enabled.has_key? type
151
- enabled[type] = []
152
- by_type[type] = []
153
- end
154
- if position
155
- enabled[type].insert(position, filter)
156
- by_type[type].insert(position, filter)
165
+ filter = Filter.new(name, type, block, true, options[:passive])
166
+ @defined[name] = filter
167
+
168
+ if options.has_key? :position
169
+ @by_type[type].insert(options[:position], filter)
157
170
  else
158
- enabled[type] << filter
159
- by_type[type] << defined[name]
171
+ @by_type[type] << filter
160
172
  end
173
+ rebuild_enabled! type
161
174
 
162
175
  filter
163
176
  end
164
177
 
165
178
  # Delete +filter+ by name or Filter object.
166
179
  def delete(filter)
167
- filter = defined[filter] unless filter.is_a? Filter
180
+ filter = @defined[filter] unless filter.is_a? Filter
168
181
  return unless filter
169
182
 
170
- defined.delete(filter.name)
171
- by_type[filter.type].delete(filter)
172
- enabled[filter.type].delete(filter)
183
+ @defined.delete(filter.name)
184
+ @by_type[filter.type].delete(filter)
185
+ rebuild_enabled! filter.type
173
186
  end
174
187
 
175
188
  # Disable +filter+ by name or Filter object.
176
189
  def off(filter)
177
- filter = defined[filter] unless filter.is_a? Filter
190
+ filter = @defined[filter] unless filter.is_a? Filter
178
191
  return unless filter
179
192
 
180
193
  filter.enabled = false
181
- enabled[filter.type].delete(filter)
194
+ rebuild_enabled! filter.type
182
195
  end
183
196
 
184
197
  # Turn on disabled +filter+ by name or Filter object.
185
198
  def on(filter)
186
- filter = defined[filter] unless filter.is_a? Filter
199
+ filter = @defined[filter] unless filter.is_a? Filter
187
200
  return unless filter
188
201
 
189
202
  filter.enabled = true
190
- enabled[filter.type] = by_type[filter.type].reject { |i| !i.enabled? }
203
+ rebuild_enabled! filter.type
191
204
  end
192
205
  end
206
+
207
+ Filters.defined = {}
208
+ Filters.by_type = Hash.new([])
209
+ Filters.active_enabled = Hash.new([])
210
+ Filters.passive_enabled = Hash.new([])
211
+ Filters.enabled = Hash.new([])
212
+
213
+ Filter = Struct.new(:name, :type, :block, :enabled, :passive) do
214
+ def call(*params); block.call(*params); end
215
+ def enabled?; enabled; end
216
+ def passive?; passive; end
217
+ end
193
218
  end
194
219
 
195
220
  Filters.add('proc', :procedure) do |content, config, *params|
@@ -218,31 +243,31 @@ module R18n
218
243
  "#{translated}[#{untranslated}]"
219
244
  end
220
245
 
221
- Filters.add('escape', :escape_html) do |content, config|
246
+ Filters.add('escape', :escape_html, :passive => true) do |content, config|
222
247
  config[:dont_escape_html] = true
223
248
  Utils.escape_html(content)
224
249
  end
225
250
 
226
- Filters.add('html', :dont_escape_html) do |content, config|
251
+ Filters.add('html', :dont_escape_html, :passive => true) do |content, config|
227
252
  config[:dont_escape_html] = true
228
253
  content
229
254
  end
230
255
 
231
- Filters.add(String, :global_escape_html) do |content, config|
256
+ Filters.add(String, :global_escape_html, :passive => true) do |html, config|
232
257
  if config[:dont_escape_html]
233
- content
258
+ html
234
259
  else
235
- Utils.escape_html(content)
260
+ Utils.escape_html(html)
236
261
  end
237
262
  end
238
263
  Filters.off(:global_escape_html)
239
264
 
240
- Filters.add('markdown', :maruku) do |content, config|
265
+ Filters.add('markdown', :maruku, :passive => true) do |content, config|
241
266
  require 'maruku'
242
267
  ::Maruku.new(content).to_html
243
268
  end
244
269
 
245
- Filters.add('textile', :redcloth) do |content, config|
270
+ Filters.add('textile', :redcloth, :passive => true) do |content, config|
246
271
  require 'redcloth'
247
272
  ::RedCloth.new(content).to_html
248
273
  end
@@ -133,10 +133,12 @@ module R18n
133
133
  path = "\#{self.class.name}##{name}"
134
134
  type = self.class.translation_types[#{name.inspect}]
135
135
  if type
136
- return R18n::Filters.process(type, result, locale, path, params)
136
+ return R18n::Filters.process(R18n::Filters.enabled,
137
+ type, result, locale, path, params)
137
138
  else
138
139
  result = TranslatedString.new(result, locale, path)
139
- return R18n::Filters.process_string(result, path, params)
140
+ return R18n::Filters.process_string(R18n::Filters.enabled,
141
+ result, path, params)
140
142
  end
141
143
  end
142
144
 
@@ -91,12 +91,15 @@ module R18n
91
91
  when Hash
92
92
  value = Translation.new(@locale, path, locale, value)
93
93
  when String
94
- value = TranslatedString.new(value, locale, path)
95
- when YAML::PrivateType
96
- value = Typed.new(value.type_id, value.value, locale, path)
94
+ v = TranslatedString.new(value, locale, path)
95
+ value = Filters.process_string(Filters.passive_enabled, v, path, {})
97
96
  when Typed
98
97
  value.locale = locale
99
98
  value.path = path
99
+ unless Filters.passive_enabled[value.type].empty?
100
+ value = Filters.process(Filters.passive_enabled, value.type,
101
+ value.value, value.locale, value.path, {})
102
+ end
100
103
  end
101
104
  @data[name] = value
102
105
  elsif @data[name].is_a? Translation
@@ -107,7 +110,8 @@ module R18n
107
110
 
108
111
  # Use untranslated filter to print path.
109
112
  def to_s
110
- Filters.process(Untranslated, @path, @locale, @path, [@path, '', @path])
113
+ Filters.process(Filters.enabled, Untranslated, @path, @locale, @path,
114
+ [@path, '', @path])
111
115
  end
112
116
 
113
117
  # Return +default+.
@@ -133,10 +137,10 @@ module R18n
133
137
  value = @data[name.to_s]
134
138
  case value
135
139
  when TranslatedString
136
- Filters.process_string(value, @path, params)
140
+ Filters.process_string(Filters.active_enabled, value, @path, params)
137
141
  when Typed
138
- Filters.process(value.type, value.value, value.locale, value.path,
139
- params)
142
+ Filters.process(Filters.active_enabled, value.type, value.value,
143
+ value.locale, value.path, params)
140
144
  when nil
141
145
  translated = @path.empty? ? '' : "#{@path}."
142
146
  Untranslated.new(translated, name.to_s, @locale)
@@ -75,7 +75,7 @@ module R18n
75
75
  end
76
76
 
77
77
  def to_s
78
- Filters.process(Untranslated, path, @locale, path,
78
+ Filters.process(Filters.enabled, Untranslated, path, @locale, path,
79
79
  [@translated_path, @untranslated_path, path])
80
80
  end
81
81
  end
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module R18n
3
- VERSION = '0.4' unless defined? R18n::VERSION
3
+ VERSION = '0.4.1' unless defined? R18n::VERSION
4
4
  end
@@ -50,7 +50,8 @@ module R18n
50
50
 
51
51
  # Return Hash with translations for +locale+.
52
52
  def load(locale)
53
- ::YAML::load(IO.read(File.join(@dir, "#{locale.code.downcase}.yml")))
53
+ file = File.join(@dir, "#{locale.code.downcase}.yml")
54
+ transform(::YAML::load(IO.read(file)))
54
55
  end
55
56
 
56
57
  # YAML loader with same +dir+ will be have same +hash+.
@@ -62,6 +63,18 @@ module R18n
62
63
  def ==(loader)
63
64
  self.class == loader.class and self.dir == loader.dir
64
65
  end
66
+
67
+ # Wrap YAML private types to Typed.
68
+ def transform(hash)
69
+ Hash[hash.map { |key, value|
70
+ if value.is_a? ::YAML::PrivateType
71
+ value = Typed.new(value.type_id, value.value)
72
+ elsif value.is_a? Hash
73
+ value = transform(value)
74
+ end
75
+ [key, value]
76
+ }]
77
+ end
65
78
  end
66
79
  end
67
80
  end
data/spec/filters_spec.rb CHANGED
@@ -6,6 +6,7 @@ describe R18n::Filters do
6
6
  @system = R18n::Filters.defined.values
7
7
  @enabled = R18n::Filters.defined.values.reject { |i| !i.enabled? }
8
8
  @i18n = R18n::I18n.new('en', DIR)
9
+ @i18n.reload!
9
10
  end
10
11
 
11
12
  after do
@@ -31,10 +32,24 @@ describe R18n::Filters do
31
32
  @i18n.my_tree_filter.should == {'name' => 'value'}
32
33
  end
33
34
 
35
+ it "should use passive filters" do
36
+ filter = mock()
37
+ filter.should_receive(:process).twice.and_return(1)
38
+
39
+ R18n::Filters.add('my', :passive, :passive => true) { filter.process }
40
+
41
+ @i18n.my_filter.should.should == 'value'
42
+ @i18n.reload!
43
+
44
+ @i18n.my_tree_filter.should == 1
45
+ @i18n.my_filter.should == 1
46
+ @i18n.my_filter.should == 1
47
+ end
48
+
34
49
  it "should use cascade filters" do
35
- filter = R18n::Filters.add('my', :one) { |i, config| i + '1' }
36
- filter = R18n::Filters.add('my', :two) { |i, config| i + '2' }
37
- filter = R18n::Filters.add('my', :three, 0) { |i, config| i + '3' }
50
+ filter = R18n::Filters.add('my', :one) { |i, config| i + '1' }
51
+ filter = R18n::Filters.add('my', :two) { |i, config| i + '2' }
52
+ filter = R18n::Filters.add('my', :three, :position => 0) { |i, c| i + '3' }
38
53
  @i18n.my_filter.should == 'value312'
39
54
  end
40
55
 
@@ -42,7 +57,7 @@ describe R18n::Filters do
42
57
  R18n::Filters.instance_variable_set(:@last_auto_name, 0)
43
58
 
44
59
  R18n::Filters.add('some').name.should == 1
45
- R18n::Filters.add('some').name.should == 2
60
+ R18n::Filters.add('some', :position => 0).name.should == 2
46
61
 
47
62
  R18n::Filters.add('some', 3)
48
63
  R18n::Filters.add('some').name.should == 4
@@ -101,7 +116,7 @@ describe R18n::Filters do
101
116
  R18n::Filters.add('my') { |content, config| config[:new_secret] ? 2 : 1 }
102
117
  @i18n.my_filter.should == 1
103
118
 
104
- R18n::Filters.add('my', nil, 0) do |content, config|
119
+ R18n::Filters.add('my', :second, :position => 0) do |content, config|
105
120
  config[:new_secret] = true
106
121
  content
107
122
  end
@@ -175,13 +190,16 @@ describe R18n::Filters do
175
190
  @i18n.greater.should == '1 < 2 is true'
176
191
 
177
192
  R18n::Filters.on(:global_escape_html)
193
+ @i18n.reload!
178
194
  @i18n.greater.should == '1 &lt; 2 is true'
179
195
  @i18n.html.should == '&lt;script&gt;true &amp;&amp; false&lt;/script&gt;'
180
196
  end
181
197
 
182
198
  it "should have filter to disable global HTML escape" do
183
199
  @i18n.no_escape.should == '<b>Warning</b>'
200
+
184
201
  R18n::Filters.on(:global_escape_html)
202
+ @i18n.reload!
185
203
  @i18n.no_escape.should == '<b>Warning</b>'
186
204
  end
187
205
 
@@ -25,8 +25,6 @@ my_filter: !!my value
25
25
  my_tree_filter: !!my
26
26
  name: value
27
27
 
28
- unknown_filter: !!unknown value
29
-
30
28
  html: !!escape
31
29
  <script>true && false</script>
32
30
  greater: 1 < 2 is true
@@ -3,3 +3,5 @@ one: Один
3
3
  in:
4
4
  another:
5
5
  level: Иерархический
6
+
7
+ typed: !!my value
@@ -23,7 +23,8 @@ describe R18n::Loader::YAML do
23
23
 
24
24
  it "should load translation" do
25
25
  @loader.load(R18n::Locale.load('ru')).should == {
26
- 'one' => 'Один', 'in' => {'another' => {'level' => 'Иерархический'}} }
26
+ 'one' => 'Один', 'in' => {'another' => {'level' => 'Иерархический'}},
27
+ 'typed' => R18n::Typed.new('my', 'value') }
27
28
  end
28
29
 
29
30
  it "should return hash by dir" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r18n-core
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.4"
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey "A.I." Sitnik
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-03 00:00:00 +03:00
12
+ date: 2010-01-11 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies: []
15
15