dgd-tools 0.1.2 → 0.1.7

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.
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