wagn 1.20.2 → 1.20.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aacbd8d9020a2bbde198f363933365b287b919e0
4
- data.tar.gz: c99bec35184f50ca1e3bb10326b325693d909518
3
+ metadata.gz: 0c371f9bcffbb3a47f5403adf9db669a2f7f75a1
4
+ data.tar.gz: f08a691bd55e343727a8469b972f2f982a8cf171
5
5
  SHA512:
6
- metadata.gz: 278a1e0e50eab3b2b77a89cd5f99455cc39e3cb3613a2ddc81f451237a4d334f54b93f0d75502a62af84e231fa7e0086c0192acad36d361a6368e5b067283c45
7
- data.tar.gz: 1a5166f2a1afe02442e37e40bdb70cfec3895911521dd6389488fbac3561eeff1bf027e7f825138f7202e48b648250db9e9c0fc7dc52ba5257466a68f00cf636
6
+ metadata.gz: 3f04c347271eef3e4208d38327395e7e84817c119da7bd4af17957c0f529fd2975f03e0f3264ca3af9c3fb60e8b44ce33d3ef7c5be94f16f68d18f3bc84fe1b0
7
+ data.tar.gz: 3f81e5e3d6a00b2082c03b8409ab5349a1f3e04e6f3183c149d4c303275a9fe06962e5f0450ee22609313008ef9fd65726f733d0ff56fea010ae64b002c28f9d
@@ -77,6 +77,7 @@ Feature: File Upload
77
77
  And I upload the image "image.png"
78
78
  And I wait for ajax response
79
79
  And I press "Submit"
80
+ And I wait for ajax response
80
81
  And I edit "Vignesh has a complicated relationship"
81
82
  And I upload the image "image2.jpg"
82
83
  And I wait for ajax response
@@ -96,6 +97,7 @@ Feature: File Upload
96
97
  And I upload the image "image.png"
97
98
  And I wait for ajax response
98
99
  And I press "Submit"
100
+ And I wait for ajax response
99
101
  And I edit "Vignesh has a complicated relationship"
100
102
  And I press "Submit"
101
103
  And I wait for ajax response
@@ -1,3 +1,4 @@
1
+ @javascript
1
2
  Feature: autonaming
2
3
  In order to save effort from thinking up names
3
4
  As an Editor
@@ -7,12 +7,9 @@ Feature: Layouts
7
7
  Background:
8
8
  Given I am signed in as Joe Admin
9
9
  And I create HTML card "simple layout" with content "Simple Header {{_main}} Simple Footer"
10
- And I wait a sec
11
10
  And the card "*all+*layout" contains "[[simple layout]]"
12
11
  And I create Pointer card "User+*type+*layout" with content "[[user layout]]"
13
- And I wait a sec
14
12
  And I create HTML card "user layout" with content "User Header {{_main}}"
15
- And I wait a sec
16
13
 
17
14
  Scenario: I visit a Basic card with the simple layout
18
15
  When I go to card "*account links"
@@ -7,12 +7,28 @@ Feature: Navbox
7
7
  Given I go to the homepage
8
8
  And I fill in "_keyword" with "Joe"
9
9
  # possible to use placeholder?
10
- And I wait a sec
10
+ And I wait a sec
11
11
  Then I should see "Joe Camel"
12
12
  And I should see "JoeNow"
13
13
  Then I press enter to search
14
- #When I follow "search: Joe"
14
+ #When I follow "search: Joe"
15
15
  # fixme: unable to click link so far...
16
16
  And I wait a sec
17
17
  Then I should see "Search results"
18
-
18
+
19
+ Scenario: wql search
20
+ Given I go to the homepage
21
+ And I fill in "_keyword" with '{"type":"User"}'
22
+ Then I press enter to search
23
+ And I wait a sec
24
+ Then I should see "Search results"
25
+ And I should see "Big Brother"
26
+
27
+ Scenario: paging
28
+ Given I go to the homepage
29
+ And I fill in "_keyword" with "skin"
30
+ Then I press enter to search
31
+ Then I should see "Search results"
32
+ And I should see "Sample Skin"
33
+ When I click on "2"
34
+ Then I should see "simplex skin+style"
@@ -15,6 +15,7 @@ Feature: Reference
15
15
  And I press "Rename"
16
16
  And I press "Rename and Update"
17
17
  And I wait for ajax response
18
+ And I wait a sec
18
19
  Then I go to card "Kawaii Man"
19
20
  And I should see "Srivigneshwar"
20
21
 
@@ -189,7 +189,7 @@ Then /^save and open all raw emails$/ do
189
189
  end
190
190
 
191
191
  Then /^(.*) should be notified that "(.*)"$/ do |username, subject|
192
- Timeout.timeout(Capybara.default_wait_time) do
192
+ Timeout.timeout(Capybara.default_max_wait_time) do
193
193
  sleep(0.5) while page.evaluate_script("jQuery.active") != 0
194
194
  end
195
195
  Delayed::Worker.new.work_off
@@ -203,7 +203,7 @@ Then /^(.*) should be notified that "(.*)"$/ do |username, subject|
203
203
  end
204
204
 
205
205
  Then /^No notification should be sent$/ do
206
- Timeout.timeout(Capybara.default_wait_time) do
206
+ Timeout.timeout(Capybara.default_max_wait_time) do
207
207
  sleep(0.5) while page.evaluate_script("jQuery.active") != 0
208
208
  end
209
209
  Delayed::Worker.new.work_off
@@ -93,26 +93,29 @@ end
93
93
 
94
94
  def set_content name, content, _cardtype=nil
95
95
  Capybara.ignore_hidden_elements = false
96
- ace_editors = all(".ace-editor-textarea[name='#{name}']")
97
- pm_editors = all(".prosemirror-editor > [name='#{name}']")
98
- if ace_editors.present? &&
99
- page.evaluate_script("typeof ace != 'undefined'")
100
- page.execute_script "ace.edit($('.ace_editor').get(0))"\
101
- ".getSession().setValue('#{content}')"
102
- elsif pm_editors.present?
103
- editor_id = pm_editors.first.first(:xpath, ".//..")[:id]
104
- set_prosemirror_content editor_id, content
105
- else
106
- # rescue Selenium::WebDriver::Error::JavascriptError
96
+ wait_for_ajax
97
+ set_ace_editor_content(name, content) ||
98
+ set_pm_editor_content(name, content) ||
107
99
  fill_in(name, with: content)
108
- end
109
100
  Capybara.ignore_hidden_elements = true
110
101
  end
111
102
 
112
- def set_prosemirror_content editor_id, content
103
+ def set_ace_editor_content name, content
104
+ return unless all(".ace-editor-textarea[name='#{name}']").present? &&
105
+ page.evaluate_script("typeof ace != 'undefined'")
106
+ sleep(0.5)
107
+ page.execute_script "ace.edit($('.ace_editor').get(0))"\
108
+ ".getSession().setValue('#{content}')"
109
+ true
110
+ end
111
+
112
+ def set_pm_editor_content name, content
113
+ (editors = all(".prosemirror-editor > [name='#{name}']"))
114
+ return unless editors.present?
115
+ editor_id = editors.first.first(:xpath, ".//..")[:id]
113
116
  escaped_quotes = content.gsub("'", "\\'")
114
- page.execute_script "getProseMirror('#{editor_id}')"\
115
- ".setContent('#{escaped_quotes}', 'text')"
117
+ page.execute_script "$('##{editor_id} .ProseMirror').text('#{escaped_quotes}')"
118
+ true
116
119
  end
117
120
 
118
121
  content_re = /^(.*) creates?\s*a?\s*([^\s]*) card "(.*)" with content "(.*)"$/
@@ -148,10 +151,16 @@ When /^(?:|I )enter "([^"]*)" into "([^"]*)"$/ do |value, field|
148
151
  end
149
152
 
150
153
  When /^(?:|I )upload the (.+) "(.+)"$/ do |attachment_name, filename|
151
- script = "$('input[type=file]').css('opacity','1');"
152
- page.driver.browser.execute_script(script)
153
- file = File.join Wagn.gem_root, "features", "support", filename
154
- attach_file "card_#{attachment_name}", file
154
+ Capybara.ignore_hidden_elements = false
155
+ attach_file "card_#{attachment_name}", find_file(filename)
156
+ Capybara.ignore_hidden_elements = true
157
+ end
158
+
159
+ def find_file filename
160
+ roots = "{#{Cardio.root}/mod/**,#{Cardio.gem_root}/mod/**,#{Wagn.gem_root}}"
161
+ paths = Dir.glob(File.join(roots, "features", "support", filename))
162
+ raise ArgumentError, "couldn't find file '#{filename}'" if paths.empty?
163
+ paths.first
155
164
  end
156
165
 
157
166
  Given /^(.*) (is|am) watching "([^\"]+)"$/ do |user, _verb, cardname|
@@ -177,19 +186,32 @@ When /I wait (\d+) seconds$/ do |period|
177
186
  sleep period.to_i
178
187
  end
179
188
 
180
- When /^I wait for ajax response$/ do
181
- Timeout.timeout(Capybara.default_wait_time) do
182
- sleep(0.5) while page.evaluate_script("jQuery.active") != 0
189
+ def wait_for_ajax
190
+ Timeout.timeout(Capybara.default_max_wait_time) do
191
+ begin
192
+ sleep(0.5) until finished_all_ajax_requests?
193
+ rescue Selenium::WebDriver::Error::UnknownError
194
+ sleep(2) # HACK: to fix the issue that in layout.feature jQuery
195
+ # after the layout change is not defined
196
+ end
183
197
  end
184
198
  end
185
199
 
200
+ def finished_all_ajax_requests?
201
+ page.evaluate_script("jQuery.active").zero?
202
+ end
203
+
204
+ When /^I wait for ajax response$/ do
205
+ wait_for_ajax
206
+ end
207
+
186
208
  # Then /what/ do
187
209
  # save_and_open_page
188
210
  # end
189
211
  #
190
212
  Then /debug/ do
191
213
  require "pry"
192
- binding.pry #
214
+ #
193
215
  nil
194
216
  end
195
217
  # if RUBY_VERSION =~ /^2/
@@ -207,6 +229,7 @@ def create_card username, cardtype, cardname, content=""
207
229
  visit "/card/new?card[name]=#{CGI.escape(cardname)}&type=#{cardtype}"
208
230
  yield if block_given?
209
231
  click_button "Submit"
232
+ wait_for_ajax
210
233
  end
211
234
  end
212
235
  end
@@ -358,7 +381,7 @@ Then /^"([^"]*)" should be selected for "([^"]*)"$/ do |value, field|
358
381
  expect(selected.inner_html).to match /#{value}/
359
382
  end
360
383
 
361
- Then /^"([^"]*)" should be signed in$/ do |user| # "
384
+ Then /^"([^"]*)" should be signed in$/ do |user| # "
362
385
  has_css?(".my-card-link", text: user)
363
386
  end
364
387
 
@@ -411,8 +434,21 @@ When /^I fill in "([^\"]*)" with$/ do |field, value|
411
434
  fill_in(field, with: value)
412
435
  end
413
436
 
437
+ When(/^I scroll (-?\d+) pixels$/) do |number|
438
+ page.execute_script "window.scrollBy(0, #{number})"
439
+ end
440
+
441
+ When(/^I scroll (\d+) pixels down$/) do |number|
442
+ page.execute_script "window.scrollBy(0, #{number})"
443
+ end
444
+
445
+ When(/^I scroll (\d+) pixels up$/) do |number|
446
+ page.execute_script "window.scrollBy(0, -#{number})"
447
+ end
448
+
414
449
  module Capybara
415
450
  module Node
451
+ # adapt capybara methods to fill in forms to wagn's form interface
416
452
  module Actions
417
453
  alias_method :original_fill_in, :fill_in
418
454
  alias_method :original_select, :select
@@ -43,6 +43,10 @@ When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
43
43
  fill_in(field, with: value)
44
44
  end
45
45
 
46
+ When /^(?:|I )fill in "([^"]*)" with '([^']*)'$/ do |field, value|
47
+ fill_in(field, with: value)
48
+ end
49
+
46
50
  When /^(?:|I )fill in "([^"]*)" for "([^"]*)"$/ do |value, field|
47
51
  fill_in(field, with: value)
48
52
  end
@@ -8,8 +8,9 @@ When /^I open a new window for (.*)$/ do |account_name|
8
8
  END_TAG
9
9
  page.execute_script(str)
10
10
  page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
11
- accounted = Card[account_name]
12
- visit "/update/:signin?card[subcards][%2B*email][content]=#{accounted.account.email}&card[subcards][%2B*password][content]=joe_pass"
11
+ email = Card[account_name].account.email
12
+ visit "/update/:signin?card[subcards][%2B*email][content]=#{email}&"\
13
+ "card[subcards][%2B*password][content]=joe_pass"
13
14
  end
14
15
 
15
16
  When /I switch to (.+) window$/ do |window|
@@ -31,12 +31,16 @@ end
31
31
  require "cucumber/rails"
32
32
  require "test_after_commit"
33
33
 
34
+ Capybara.register_driver :selenium do |app|
35
+ Capybara::Selenium::Driver.new(app, browser: :chrome)
36
+ end
37
+
34
38
  # Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In
35
39
  # order to ease the transition to Capybara we set the default here. If you'd
36
40
  # prefer to use XPath just remove this line and adjust any selectors in your
37
41
  # steps to use the XPath syntax.
38
42
  Capybara.default_selector = :css
39
- Capybara.default_wait_time = 5
43
+ Capybara.default_max_wait_time = 20
40
44
  Cardio.config.paging_limit = 10
41
45
  # By default, any exception happening in your Rails application will bubble up
42
46
  # to Cucumber so that your scenario will fail. This is a different from how
@@ -6,5 +6,9 @@
6
6
  # Make sure the secret is at least 30 characters and all random,
7
7
  # no regular words or you'll be exposed to dictionary attacks.
8
8
 
9
- Wagn.config.secret_token = "65632e048d6c80d1e63c911e1a40a51072413543f3182e0261b52e3812b2c9f0ee81828fa5688a34c13a78e438a4b56f497135dc079a4e4460733d555968a2f8"
10
- Wagn.config.secret_key_base = "65632e048d6c80d1e63c911e1a40a51072413543f3182e0261b52e3812b2c9f0ee81828fa5688a34c13a78e438a4b56f497135dc079a4e4460733d555968a2f8"
9
+ Wagn.config.secret_token = "65632e048d6c80d1e63c911e1a40a51072413543f3182e0261"\
10
+ "b52e3812b2c9f0ee81828fa5688a34c13a78e438a4b56f4971"\
11
+ "35dc079a4e4460733d555968a2f8"
12
+ Wagn.config.secret_key_base = "65632e048d6c80d1e63c911e1a40a51072413543f3182e0"\
13
+ "261b52e3812b2c9f0ee81828fa5688a34c13a78e438a4b5"\
14
+ "6f497135dc079a4e4460733d555968a2f8"
@@ -90,7 +90,8 @@ group :test do
90
90
  # CUKES see features dir
91
91
  gem 'cucumber-rails', '~> 1.4', :require=>false # feature-driven-development suite
92
92
  gem 'capybara', '~> 2.7'
93
- gem 'selenium-webdriver', '~> 2.53'
93
+ gem 'selenium-webdriver', '~> 3.3'
94
+ gem 'chromedriver-helper', '~> 1.0.0'
94
95
  # gem 'capybara-webkit'
95
96
  gem 'launchy' # lets cucumber launch browser windows
96
97
 
@@ -17,7 +17,7 @@ class WagnGenerator < Rails::Generators::AppBase
17
17
  desc: "Prepare deck for wagn core testing"
18
18
 
19
19
  class_option "gem-path",
20
- type: :string, aliases: "-g", default: false, group: :runtime,
20
+ type: :string, aliases: "-g", default: "", group: :runtime,
21
21
  desc: "Path to local gem installation " \
22
22
  "(Default, use env WAGN_GEM_PATH)"
23
23
 
@@ -157,7 +157,7 @@ class WagnGenerator < Rails::Generators::AppBase
157
157
  protected
158
158
 
159
159
  def core_dev_setup
160
- unless @gem_path
160
+ if @gem_path.blank?
161
161
  @gemfile_gem_path =
162
162
  @gem_path = ask("Enter the path to your local wagn gem installation: ")
163
163
  end
@@ -171,7 +171,7 @@ class WagnGenerator < Rails::Generators::AppBase
171
171
  @wagn_gem_root = File.join @gem_path, "wagn"
172
172
  inside "spec" do
173
173
  template File.join("javascripts", "support", "wagn_jasmine.yml"),
174
- File.join("javascripts", "support", "jasmine.yml")
174
+ File.join("javascripts", "support", "jasmine.yml")
175
175
  end
176
176
 
177
177
  # ending slash is important in order to load support and step folders
@@ -188,7 +188,7 @@ class WagnGenerator < Rails::Generators::AppBase
188
188
  inside "spec" do
189
189
  template "spec_helper.rb"
190
190
  template File.join("javascripts", "support", "deck_jasmine.yml"),
191
- File.join("javascripts", "support", "jasmine.yml")
191
+ File.join("javascripts", "support", "jasmine.yml")
192
192
  end
193
193
  end
194
194
 
@@ -242,6 +242,7 @@ class WagnGenerator < Rails::Generators::AppBase
242
242
  @app_const_base ||= defined_app_const_base ||
243
243
  app_name.gsub(/\W/, "_").squeeze("_").camelize
244
244
  end
245
+
245
246
  alias camelized app_const_base
246
247
 
247
248
  def app_const
@@ -250,13 +251,13 @@ class WagnGenerator < Rails::Generators::AppBase
250
251
 
251
252
  def valid_const?
252
253
  if app_const =~ /^\d/
253
- raise Error, "Invalid application name #{app_name}. " \
254
+ raise Thor::Error, "Invalid application name #{app_name}. " \
254
255
  "Please give a name which does not start with numbers."
255
256
  # elsif RESERVED_NAMES.include?(app_name)
256
257
  # raise Error, "Invalid application name #{app_name}." \
257
258
  # "Please give a name which does not match one of the reserved rails words."
258
259
  elsif Object.const_defined?(app_const_base)
259
- raise Error, "Invalid application name #{app_name}, " \
260
+ raise Thor::Error, "Invalid application name #{app_name}, " \
260
261
  "constant #{app_const_base} is already in use. " \
261
262
  "Please choose another application name."
262
263
  end
@@ -2,7 +2,8 @@ require "pathname"
2
2
 
3
3
  module Wagn
4
4
  module ScriptWagnLoader
5
- RUBY = File.join(*RbConfig::CONFIG.values_at("bindir", "ruby_install_name")) + RbConfig::CONFIG["EXEEXT"]
5
+ RUBY = File.join(*RbConfig::CONFIG.values_at("bindir", "ruby_install_name")) +
6
+ RbConfig::CONFIG["EXEEXT"]
6
7
  SCRIPT_WAGN = File.join("script", "wagn")
7
8
 
8
9
  def self.exec_script_wagn!
@@ -23,7 +24,8 @@ module Wagn
23
24
  end
24
25
 
25
26
  def self.in_wagn_application_subdirectory? path=Pathname.new(Dir.pwd)
26
- File.exist?(File.join(path, SCRIPT_WAGN)) || !path.root? && in_wagn_application_subdirectory?(path.parent)
27
+ File.exist?(File.join(path, SCRIPT_WAGN)) ||
28
+ !path.root? && in_wagn_application_subdirectory?(path.parent)
27
29
  end
28
30
  end
29
31
  end
@@ -268,9 +268,9 @@ describe CardController do
268
268
  context "file" do
269
269
  before do
270
270
  Card::Auth.as_bot do
271
- Card.create name: "mao2", type_code: "image",
272
- image: File.new(File.join(FIXTURES_PATH, "mao2.jpg"))
273
- Card.create name: "mao2+*self+*read", content: "[[Administrator]]"
271
+ Card.create! name: "mao2", type_code: "image",
272
+ image: File.new(File.join(FIXTURES_PATH, "mao2.jpg"))
273
+ Card.create! name: "mao2+*self+*read", content: "[[Administrator]]"
274
274
  end
275
275
  end
276
276
 
@@ -43,7 +43,9 @@ unless defined? TEST_ROOT
43
43
  renames = { "layout_type" => "Layout", "search_type" => "Search" }
44
44
  if card = Card["Sample #{renames[cardtype] || cardtype}"]
45
45
  url.gsub!(/:id/, "~#{card.id}")
46
- else puts("ERROR finding 'Sample #{cardtype}'") end
46
+ else
47
+ puts("ERROR finding 'Sample #{cardtype}'")
48
+ end
47
49
  end
48
50
  url
49
51
  end
@@ -64,14 +66,15 @@ unless defined? TEST_ROOT
64
66
  constant = (name.camelize + "TestHelper").constantize
65
67
  class_eval { include constant }
66
68
  rescue NameError
67
- filename = File.expand_path(TEST_ROOT + "/helpers/" + name + "_test_helper.rb")
68
- require filename if first_time
69
+ filename = "#{name}_test_helper.rb"
70
+ filepath = File.expand_path(File.join(TEST_ROOT, "helpers", filename))
71
+ require filepath if first_time
69
72
  first_time = false
70
73
  retry
71
74
  end
72
75
  end
73
76
  end
74
- alias test_helpers test_helper
77
+ alias_method :test_helpers, :test_helper
75
78
  end
76
79
 
77
80
  class RenderTest
@@ -86,27 +89,30 @@ unless defined? TEST_ROOT
86
89
  # FIXME: need a better data source for this?
87
90
  # args[:cardtypes] = YAML.load_file('db/bootstrap/card_codenames.yml').
88
91
  bootstrap_file = File.join(Cardio.gem_root, "db/bootstrap/cards.yml")
89
- args[:cardtypes] = YAML.load_file(bootstrap_file).select do |p|
92
+ cardtypes = YAML.load_file(bootstrap_file).select do |p|
90
93
  !%w(set setting).member?(p[1]["codename"]) &&
91
94
  (card = Card[p[1]["name"]]) && card.type_id == Card::CardtypeID
92
- end.map { |_k, v| v["codename"] }
95
+ end
96
+ args[:cardtypes] = cardtypes.map { |_k, v| v["codename"] }
93
97
  end
94
98
 
95
99
  args[:users].each_pair do |user, status|
96
100
  user = user.to_s
97
- current_id = Integer === user ? user : Card[user].id
101
+ current_id = user.is_a?(Integer) ? user : Card[user].id
98
102
 
99
103
  args[:cardtypes].each do |cardtype|
100
104
  next if cardtype =~ /Cardtype|UserForm|Set|Fruit|Optic|Book/
101
105
 
102
- title = url.gsub(/:id/, "").gsub(/\//, "_") + "_#{cardtype}"
103
- login = (current_id == Card::AnonymousID ? "" : "integration_login_as '#{user}'")
106
+ title = url.gsub(/:id/, "").tr("/", "_") + "_#{cardtype}"
107
+ login =
108
+ (current_id == Card::AnonymousID ? "" : "integration_login_as '#{user}'")
104
109
  test_def = %{
105
110
  def test_render_#{title}_#{user}_#{status}
106
111
  #{login}
107
112
  url = prepare_url('#{url}', '#{cardtype}')
108
113
  get url
109
- assert_response #{status}, "\#\{url\} as #{user} should have status #{status}"
114
+ assert_response #{status},
115
+ "\#\{url\} as #{user} should have status #{status}"
110
116
  end
111
117
  }
112
118
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wagn
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.20.2
4
+ version: 1.20.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan McCutchen
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-03-02 00:00:00.000000000 Z
14
+ date: 2017-04-13 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rails
@@ -33,14 +33,14 @@ dependencies:
33
33
  requirements:
34
34
  - - '='
35
35
  - !ruby/object:Gem::Version
36
- version: 1.20.2
36
+ version: 1.20.3
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - '='
42
42
  - !ruby/object:Gem::Version
43
- version: 1.20.2
43
+ version: 1.20.3
44
44
  description: a wiki approach to stuctured data, dynamic interaction, and web design
45
45
  email:
46
46
  - info@wagn.org