dgd-tools 0.1.2 → 0.1.7

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
  SHA256:
3
- metadata.gz: bf28b15e9e5aa7fe5c3d52835011e37c2b34f8ed839b59e6faea3ff9b23433d7
4
- data.tar.gz: 66d8280067875fe8dfbb056e3288dec4471eba855937ee182dd24db70f30cd9b
3
+ metadata.gz: 2b3639fa674b53796ffe654f0e7e0deb9506868eece4550b99b4f28b98940e97
4
+ data.tar.gz: b0f115747b8f790ba079a9789d18e5bbe024de6e9b1c6cc1c476d21066a1b48a
5
5
  SHA512:
6
- metadata.gz: 79fb4a29346b26de15f1cf4b6fe0c81ad845f45e24688b83f91f03c6aca61b691b6fb0698d64eb2fd633ae0f52d8df2bdb2226549ba524d748201b8f728adab2
7
- data.tar.gz: 1f4ffe31a23b5f0302b0d47815c74a4484847cfd9afce393d37c85515be981943447d5807eef11bca221269c2cde7c3137e5868561f306e8d83035ac5d03dd5b
6
+ metadata.gz: c739260975e503e32a44bfeaf4775d6693e606f35a247f6d432008d0b9e813ac7b29208d1db641dee46be7aec8bbb86e92c1f8fe7e9c7b1c2aadb2ce93e4fb8e
7
+ data.tar.gz: 50cc3537969a52ca379857a8936b900212e18567bdc10c1cb1152cffb7901f88db53b75a04126b8848e0edb3151d74a4514cc3fe02d7c1ae1f0ece0cbbe7d6f3
data/.gitignore CHANGED
@@ -7,3 +7,5 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  *.gem
10
+ test/data/**/dgd.config
11
+ test/data/*/.root
data/Gemfile.lock CHANGED
@@ -1,12 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dgd-tools (0.1.2)
4
+ dgd-tools (0.1.7)
5
+ nokogiri (~> 1.10.5)
6
+ optimist (~> 3.0.1)
5
7
 
6
8
  GEM
7
9
  remote: https://rubygems.org/
8
10
  specs:
11
+ mini_portile2 (2.4.0)
9
12
  minitest (5.14.2)
13
+ nokogiri (1.10.10)
14
+ mini_portile2 (~> 2.4.0)
15
+ optimist (3.0.1)
10
16
  rake (12.3.3)
11
17
 
12
18
  PLATFORMS
data/README.md CHANGED
@@ -14,6 +14,18 @@ DGD Manifest is a simple initial library system. I'm sure I'll figure more out a
14
14
 
15
15
  This work has grown out of [SkotOS and ChatTheatre](https://github.com/ChatTheatre) tasks.
16
16
 
17
+ You can find example DGD manifest files under the "test" directory and also in [various](https://github.com/noahgibbs/prototype_vRWOT) [SkotOS-based games](https://github.com/ChatTheatre/gables_game) that use the DGD Manifest system.
18
+
19
+ You can find example "goods" (library) files under the "goods" subdirectory of this repo.
20
+
21
+ ## WOE Objects and skotos-xml-diff
22
+
23
+ SkotOS-based games use an XML format for in-game objects called WOE, which is [documented in SkotOS-Doc](https://ChatTheatre.github.io/SkotOS-Doc). The skotos-xml-diff utility will diff between WOE objects or directories of WOE objects.
24
+
25
+ See SkotOS-Doc for more detail about how this can be used with a SkotOS game.
26
+
27
+ Run "skotos-xml-diff --help" for a list of options. You can tell it to ignore whitespace, to diff only the Merry (script) contents of the objects, and to ignore certain XML node types.
28
+
17
29
  ## Installation
18
30
 
19
31
  You would normally install DGDTools directly: `gem install dgd-tools`.
@@ -26,6 +38,8 @@ If you have a DGD application that uses DGD Manifest, run `dgd-manifest install`
26
38
 
27
39
  That fully-assembled DGD directory is named ".root". To run your dgd server, type "dgd-manifest server".
28
40
 
41
+ If you update files in your root and want to update files under the generated root directory, use "dgd-manifest update".
42
+
29
43
  ## Using DGD Manifest with your DGD Application
30
44
 
31
45
  Your app will need a dgd.manifest file, which is a lot like NPM's package.json file.
data/bin/console CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "bundler/setup"
4
4
  require "dgd-tools/manifest"
5
+ require "dgd-tools/skotos_xml_obj"
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
data/dgd-tools.gemspec CHANGED
@@ -23,4 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.bindir = "exe"
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ["lib"]
26
+
27
+ spec.add_runtime_dependency "nokogiri", "~>1.10.5"
28
+ spec.add_runtime_dependency "optimist", "~>3.0.1"
26
29
  end
@@ -0,0 +1,42 @@
1
+ <object program="/base/sys/craftd">
2
+ <Base:CraftDaemon>
3
+ <Base:Craftables>
4
+ <Base:Craftable item="OBJ(Regent:Props:Fabric:blanket)"/>
5
+ <Base:Craftable item="OBJ(Regent:Staff:Evett:Items:Clothes:Top)"/>
6
+ <Base:Craftable item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
7
+ <Base:Craftable item="OBJ(Regent:Staff:Debbie:IC:General:orderbook)"/>
8
+ </Base:Craftables>
9
+ <Base:AllTools>
10
+ <Base:AllToolDependents tool="mop floor"/>
11
+ <Base:AllToolDependents tool="new">
12
+ <Base:OneToolDependent item="OBJ(Regent:Props:Fabric:blanket)"/>
13
+ <Base:OneToolDependent item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
14
+ <Base:OneToolDependent item="OBJ(Regent:Staff:Debbie:IC:General:orderbook)"/>
15
+ </Base:AllToolDependents>
16
+ <Base:AllToolDependents tool="regent:props:sewing:tools:needle"/>
17
+ <Base:AllToolDependents tool="regent:props:sewing:tools:scissors"/>
18
+ <Base:AllToolDependents tool="tool:heatable:container:watertight"/>
19
+ <Base:AllToolDependents tool="tool:heatsource:fire"/>
20
+ <Base:AllToolDependents tool="tools:needle">
21
+ <Base:OneToolDependent item="OBJ(Regent:Props:Fabric:blanket)"/>
22
+ <Base:OneToolDependent item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
23
+ </Base:AllToolDependents>
24
+ </Base:AllTools>
25
+ <Base:AllIngredients>
26
+ <Base:AllIngredientDependents ingredient="bolt">
27
+ <Base:OneIngredientDependent item="OBJ(Regent:Props:Fabric:blanket)"/>
28
+ <Base:OneIngredientDependent item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
29
+ </Base:AllIngredientDependents>
30
+ <Base:AllIngredientDependents ingredient="ingredient:candle"/>
31
+ <Base:AllIngredientDependents ingredient="ingredient:lantern-candle-empty"/>
32
+ <Base:AllIngredientDependents ingredient="ingredient:lantern:candle"/>
33
+ <Base:AllIngredientDependents ingredient="ingredients:tallow"/>
34
+ <Base:AllIngredientDependents ingredient="ingredients:wick:hemp"/>
35
+ <Base:AllIngredientDependents ingredient="new">
36
+ <Base:OneIngredientDependent item="OBJ(Regent:Props:Fabric:blanket)"/>
37
+ <Base:OneIngredientDependent item="OBJ(Regent:Staff:Evett:Items:Clothes:Top)"/>
38
+ <Base:OneIngredientDependent item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
39
+ </Base:AllIngredientDependents>
40
+ </Base:AllIngredients>
41
+ </Base:CraftDaemon>
42
+ </object>
@@ -0,0 +1,3 @@
1
+ <object program="/base/sys/materials">
2
+ <Base:Materials/>
3
+ </object>
@@ -0,0 +1,49 @@
1
+ <object program="/base/sys/properties">
2
+ <Base:PropertyTypes>
3
+ <Base:PropertyTypeIntList>
4
+ <Base:PropertyTypeInt property="page:allowall"/>
5
+ <Base:PropertyTypeInt property="skill:advancedefensive"/>
6
+ <Base:PropertyTypeInt property="skill:attackingdefensive"/>
7
+ <Base:PropertyTypeInt property="skill:cutoffensive"/>
8
+ <Base:PropertyTypeInt property="skill:dodgedefensive"/>
9
+ <Base:PropertyTypeInt property="skill:feintoffensive"/>
10
+ <Base:PropertyTypeInt property="skill:fumbledefensive"/>
11
+ <Base:PropertyTypeInt property="skill:guarddefensive"/>
12
+ <Base:PropertyTypeInt property="skill:idledefensive"/>
13
+ <Base:PropertyTypeInt property="skill:lang1"/>
14
+ <Base:PropertyTypeInt property="skill:lang2"/>
15
+ <Base:PropertyTypeInt property="skill:lang3"/>
16
+ <Base:PropertyTypeInt property="skill:lang4"/>
17
+ <Base:PropertyTypeInt property="skill:lang5"/>
18
+ <Base:PropertyTypeInt property="skill:lang6"/>
19
+ <Base:PropertyTypeInt property="skill:lang7"/>
20
+ <Base:PropertyTypeInt property="skill:recoverdefensive"/>
21
+ <Base:PropertyTypeInt property="skill:restdefensive"/>
22
+ <Base:PropertyTypeInt property="skill:retiredefensive"/>
23
+ <Base:PropertyTypeInt property="skill:salutedefensive"/>
24
+ <Base:PropertyTypeInt property="skill:teaching"/>
25
+ <Base:PropertyTypeInt property="skill:thrustoffensive"/>
26
+ <Base:PropertyTypeInt property="skill_study"/>
27
+ <Base:PropertyTypeInt property="skotos:currentlang"/>
28
+ </Base:PropertyTypeIntList>
29
+ <Base:PropertyTypeFloatList>
30
+ <Base:PropertyTypeFloat property="skill:fatigue"/>
31
+ </Base:PropertyTypeFloatList>
32
+ <Base:PropertyTypeStringList>
33
+ <Base:PropertyTypeString property="skotos:charname"/>
34
+ <Base:PropertyTypeString property="skotos:creator"/>
35
+ </Base:PropertyTypeStringList>
36
+ <Base:PropertyTypeObjectList>
37
+ <Base:PropertyTypeObject property="virtualhome:home"/>
38
+ <Base:PropertyTypeObject property="virtualhome:oubliette"/>
39
+ </Base:PropertyTypeObjectList>
40
+ <Base:PropertyTypeArrayList>
41
+ <Base:PropertyTypeArray property="startstory:skilllist:done"/>
42
+ <Base:PropertyTypeArray property="startstory:skilllist:left"/>
43
+ </Base:PropertyTypeArrayList>
44
+ <Base:PropertyTypeMappingList>
45
+ <Base:PropertyTypeMapping property="page:allow"/>
46
+ <Base:PropertyTypeMapping property="page:pending"/>
47
+ </Base:PropertyTypeMappingList>
48
+ </Base:PropertyTypes>
49
+ </object>
@@ -0,0 +1,41 @@
1
+ <object program="/base/obj/thing">
2
+ <Base:Thing>
3
+ <Ur:UrObject/>
4
+ <Base:Bulk immobile="false" mass="1" density="1"/>
5
+ <Base:Container flexible="false" transparent-container="false" public-container="false" tight="false" capacity="0" maxweight="0"/>
6
+ <Base:Misc gender="neuter" volition="false" weapon="false" default_stance="none" combinable="false" discrete="false" by_weight="false" tight="false" scriptrunner="false">
7
+ <Base:Edible value="false"/>
8
+ <Base:Potable value="false"/>
9
+ <Base:DrinkMessageFirst/>
10
+ <Base:DrinkMessageThird/>
11
+ <Base:Transparency value="false"/>
12
+ <Base:Unsafe value="false"/>
13
+ <Base:Safe value="false"/>
14
+ <Base:ClothesExpected value="false"/>
15
+ <Base:DieMessageFirst/>
16
+ <Base:DieMessageThird/>
17
+ </Base:Misc>
18
+ <Base:Details/>
19
+ <Base:Combat>
20
+ <Base:Strength value="1"/>
21
+ <Base:MaxFatigue value="1"/>
22
+ </Base:Combat>
23
+ <Base:Clothing>
24
+ <Base:SingleWear value="false"/>
25
+ </Base:Clothing>
26
+ <Base:Crafting see_level="0" do_level="0" time="0" attention="false" held="false">
27
+ <Base:Ingredients/>
28
+ <Base:Tools/>
29
+ <Base:CraftVerbs/>
30
+ </Base:Crafting>
31
+ <Base:InitialContents/>
32
+ <Base:InitialProperties/>
33
+ <Core:Properties>
34
+ <Core:Property property="revisions">
35
+ (\{ 1065557891, "the_exiled", "E" \})
36
+ </Core:Property>
37
+ <Core:Property property="skill:fatigue">1.0</Core:Property>
38
+ </Core:Properties>
39
+ <Notes:Notes/>
40
+ </Base:Thing>
41
+ </object>
@@ -0,0 +1,42 @@
1
+ <object program="/base/obj/thing" owner="bobo">
2
+ <Base:Thing>
3
+ <Ur:UrObject/>
4
+ <Base:Bulk immobile="false" mass="1" density="1"/>
5
+ <Base:Container flexible="false" transparent-container="false" public-container="false" tight="false" capacity="0" maxweight="0"/>
6
+ <Base:Misc gender="neuter" volition="false" weapon="false" default_stance="none" combinable="false" discrete="false" by_weight="false" tight="false" scriptrunner="false" bogusfield="nope">
7
+ <Base:Edible value="false"/>
8
+ <Base:Potable value="false"/>
9
+ <Base:DrinkMessageFirst/>
10
+ <Base:DrinkMessageThird/>
11
+ <Base:Transparency value="false"/>
12
+ <Base:Unsafe value="false"/>
13
+ <Base:Safe value="false"/>
14
+ <Base:ClothesExpected value="false"/>
15
+ <Base:DieMessageFirst/>
16
+ <Base:DieMessageThird/>
17
+ <Base:DieMessageFortySecond/>
18
+ </Base:Misc>
19
+ <Base:Details/>
20
+ <Base:Combat>
21
+ <Base:Strength value="1"/>
22
+ <Base:MaxFatigue value="1"/>
23
+ </Base:Combat>
24
+ <Base:Clothing>
25
+ <Base:SingleWear value="false"/>
26
+ </Base:Clothing>
27
+ <Base:Crafting see_level="0" do_level="0" time="0" attention="false" held="false">
28
+ <Base:Ingredients/>
29
+ <Base:Tools/>
30
+ <Base:CraftVerbs/>
31
+ </Base:Crafting>
32
+ <Base:InitialContents/>
33
+ <Base:InitialProperties/>
34
+ <Core:Properties>
35
+ <Core:Property property="revisions">
36
+ (\{ 1065557891, "the_exiled", "E" \})
37
+ </Core:Property>
38
+ <Core:Property property="skill:fatigue">1.0</Core:Property>
39
+ </Core:Properties>
40
+ <Notes:Notes/>
41
+ </Base:Thing>
42
+ </object>
@@ -0,0 +1,41 @@
1
+ <object program="/base/obj/thing">
2
+ <Base:Thing>
3
+ <Ur:UrObject/>
4
+ <Base:Bulk immobile="false" mass="1" density="1"/>
5
+ <Base:Container flexible="false" transparent-container="false" public-container="false" tight="false" capacity="0" maxweight="0"/>
6
+ <Base:Misc gender="neuter" volition="false" weapon="false" default_stance="none" combinable="false" discrete="false" by_weight="false" tight="false" scriptrunner="false">
7
+ <Base:Edible value="false"/>
8
+ <Base:Potable value="false"/>
9
+ <Base:DrinkMessageFirst/>
10
+ <Base:DrinkMessageThird/>
11
+ <Base:Transparency value="false"/>
12
+ <Base:Unsafe value="false"/>
13
+ <Base:Safe value="false"/>
14
+ <Base:ClothesExpected value="false"/>
15
+ <Base:DieMessageFirst/>
16
+ <Base:DieMessageThird/>
17
+ </Base:Misc>
18
+ <Base:Details/>
19
+ <Base:Combat>
20
+ <Base:Strength value="1"/>
21
+ <Base:MaxFatigue value="1"/>
22
+ </Base:Combat>
23
+ <Base:Clothing>
24
+ <Base:SingleWear value="false"/>
25
+ </Base:Clothing>
26
+ <Base:Crafting see_level="0" do_level="0" time="0" attention="false" held="false">
27
+ <Base:Ingredients/>
28
+ <Base:Tools/>
29
+ <Base:CraftVerbs/>
30
+ </Base:Crafting>
31
+ <Base:InitialContents/>
32
+ <Base:InitialProperties/>
33
+ <Core:Properties>
34
+ <Core:Property property="revisions">
35
+ (\{ 1065557891, "the_exiled", "E" \})
36
+ </Core:Property>
37
+ <Core:Property property="skill:fatigue">1.0</Core:Property>
38
+ </Core:Properties>
39
+ <Notes:Notes/>
40
+ </Base:Thing>
41
+ </object>
@@ -0,0 +1,42 @@
1
+ <object program="/base/obj/thing" owner="bobo">
2
+ <Base:Thing>
3
+ <Ur:UrObject/>
4
+ <Base:Bulk immobile="false" mass="1" density="1"/>
5
+ <Base:Container flexible="false" transparent-container="false" public-container="false" tight="false" capacity="0" maxweight="0"/>
6
+ <Base:Misc gender="neuter" volition="false" weapon="false" default_stance="none" combinable="false" discrete="false" by_weight="false" tight="false" scriptrunner="false" bogusfield="nope">
7
+ <Base:Edible value="false"/>
8
+ <Base:Potable value="false"/>
9
+ <Base:DrinkMessageFirst/>
10
+ <Base:DrinkMessageThird/>
11
+ <Base:Transparency value="false"/>
12
+ <Base:Unsafe value="false"/>
13
+ <Base:Safe value="false"/>
14
+ <Base:ClothesExpected value="false"/>
15
+ <Base:DieMessageFirst/>
16
+ <Base:DieMessageThird/>
17
+ <Base:DieMessageFortySecond/>
18
+ </Base:Misc>
19
+ <Base:Details/>
20
+ <Base:Combat>
21
+ <Base:Strength value="1"/>
22
+ <Base:MaxFatigue value="1"/>
23
+ </Base:Combat>
24
+ <Base:Clothing>
25
+ <Base:SingleWear value="false"/>
26
+ </Base:Clothing>
27
+ <Base:Crafting see_level="0" do_level="0" time="0" attention="false" held="false">
28
+ <Base:Ingredients/>
29
+ <Base:Tools/>
30
+ <Base:CraftVerbs/>
31
+ </Base:Crafting>
32
+ <Base:InitialContents/>
33
+ <Base:InitialProperties/>
34
+ <Core:Properties>
35
+ <Core:Property property="revisions">
36
+ (\{ 1065557891, "the_exiled", "E" \})
37
+ </Core:Property>
38
+ <Core:Property property="skill:fatigue">1.0</Core:Property>
39
+ </Core:Properties>
40
+ <Notes:Notes/>
41
+ </Base:Thing>
42
+ </object>
data/exe/dgd-manifest CHANGED
@@ -6,7 +6,31 @@ if ARGV.size == 0
6
6
  ARGV.push "install"
7
7
  end
8
8
 
9
+ if ARGV == ["--version"]
10
+ puts "dgd-tools version #{DGD::VERSION}"
11
+ exit
12
+ end
13
+
14
+ if ARGV.size == 1 && ["-h", "--help"].include?(ARGV[0])
15
+ puts <<HELP_INFO
16
+ dgd-manifest commands:
17
+
18
+ new [project_name]: create a new DGD-manifest project
19
+ test: make sure the dgd.manifest file is well-formed and usable
20
+ install: compile the DGD application to a config file and a root directory
21
+ HELP_INFO
22
+ exit
23
+ end
24
+
9
25
  case ARGV[0]
26
+ when "new"
27
+ unless ARGV.size == 2
28
+ puts "Usage: dgd-manifest new [project name]"
29
+ raise "Must supply exactly one argument to dgd-manifest new!"
30
+ end
31
+ appdir = DGD::Manifest::AppDirectory.new(File.expand_path ARGV[1])
32
+ appdir.name = ARGV[1]
33
+ appdir.create!
10
34
  when "test"
11
35
  unless File.exist?("dgd.manifest")
12
36
  raise "I don't see a dgd.manifest file in this directory!"
@@ -14,6 +38,7 @@ when "test"
14
38
  puts "Running dgd.manifest installer..."
15
39
  repo = DGD::Manifest::Repo.new
16
40
  repo.manifest_file("dgd.manifest")
41
+ repo.precheck(".")
17
42
  puts "Verified Manifest packages: this looks likely correct."
18
43
  when "install"
19
44
  unless File.exist?("dgd.manifest")
@@ -22,7 +47,21 @@ when "install"
22
47
  puts "Running DGD Manifest installer..."
23
48
  repo = DGD::Manifest::Repo.new
24
49
  repo.manifest_file("dgd.manifest")
25
- repo.assemble_app(".")
50
+ current_dir = File.expand_path(".")
51
+ repo.precheck(current_dir)
52
+ repo.assemble_app(current_dir)
53
+ puts "Assembled DGD application into #{current_dir}"
54
+ when "update"
55
+ unless File.exist?("dgd.manifest")
56
+ raise "I don't see a dgd.manifest file in this directory!"
57
+ end
58
+ puts "Running DGD Manifest installer..."
59
+ repo = DGD::Manifest::Repo.new
60
+ repo.manifest_file("dgd.manifest")
61
+ current_dir = File.expand_path(".")
62
+ repo.precheck(current_dir)
63
+ repo.update_app(current_dir)
64
+ puts "Updated DGD application in #{current_dir}"
26
65
  when "server"
27
66
  puts "Starting DGD server..."
28
67
  DGD::Manifest.system_call("~/.dgd-tools/dgd/bin/dgd dgd.config")
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Diff multiple Skotos-XML-format objects dumped from a
4
+ # SkotOS-or-similar game to find out what updates should
5
+ # be merged between them.
6
+
7
+ require 'optimist'
8
+ require "dgd-tools/skotos_xml_obj"
9
+
10
+ OPTS = Optimist::options do
11
+ version "DGD-tools version #{DGD::VERSION}"
12
+ banner <<BANNER
13
+ Usage:
14
+ skotos-xml-diff [options] <file_or_dir_1> <file_or_dir_2>
15
+ where [options] are:
16
+ BANNER
17
+ opt :merry_only, "Only diff Merry scripts"
18
+ opt :ignore_whitespace, "Ignore whitespace in final diff"
19
+ opt :ignore_types, "Comma-separated list of XML node types to ignore (e.g. Combat:Base,Base:Exit)", type: :string
20
+ end
21
+
22
+ Optimist::die "Supply exactly two files or directories -- you supplied #{ARGV.size}!" unless ARGV.size == 2
23
+ Optimist::die "Supply both files or both directories, not one of each!" if File.directory?(ARGV[0]) ^ File.directory?(ARGV[1])
24
+
25
+ SkotOS::XMLObject.merry_only = true if OPTS[:merry_only]
26
+ SkotOS::XMLObject.ignore_whitespace = true if OPTS[:ignore_whitespace]
27
+ SkotOS::XMLObject.ignore_types = OPTS[:ignore_types].split(",") if OPTS[:ignore_types]
28
+
29
+ if File.directory?(ARGV[0])
30
+ diff = SkotOS::XMLObject.diff_dirs(*ARGV)
31
+ if diff.empty?
32
+ puts "No difference."
33
+ else
34
+ puts diff.join("\n\n=====\n\n")
35
+ end
36
+ else
37
+ obj1 = SkotOS::XMLObject.from_file(ARGV[0])
38
+ obj2 = SkotOS::XMLObject.from_file(ARGV[1])
39
+ diff = SkotOS::XMLObject.diff_between(obj1, obj2)
40
+ if diff.empty?
41
+ puts "No difference."
42
+ else
43
+ puts diff
44
+ end
45
+ end