This may very well apply only to me…
I would like to re-use some shell and Dart benchmarking code. I will not be duplicating code so I have to find a working solution. The problem with which I am faced is that I am not working on a single Dart package, but dozens—one for each pattern that will be covered in Design Patterns in Dart. Each package has its own internal Dart Pub structure, complete with
pubspec.yaml
and the usual subdirectories:$ tree -L 2 . ├── factory_method │ ├── build │ ├── lib │ ├── packages │ ├── pubspec.lock │ ├── pubspec.yaml │ ├── tool │ └── web └── visitor ├── bin ├── lib ├── packages ├── pubspec.lock ├── pubspec.yaml └── toolThe code that I would like to share currently exists only in the Visitor Pattern's
tool
subdirectory. I suppose that I could create another top-level directory like helpers
and then import the common code into visitor
, factory_method
and the still-to-be-written directories. That seems like a recipe for an unmaintainable codebase—I will wind up with crazy depths and amounts of relative imports (e.g. import '../../../../helpers/benchmark.dart'
) strewn about. And the coding gods help me should I ever want to rename things.Instead, I think that I will create a top-level
packages
directory to hold my common benchmarking code, as well as any other common code that I might want to use. As the name suggests, I can create this as an actual Dart Pub package, but instead of publishing it to pub.dartlang.org, I can keep it local:$ tree -L 2 . ├── factory_method │ └── ... ├── packages │ └── benchmarking └── visitor └── ...I am probably going to regret this, but I named the package's subdirectory as the relatively brief ”benchmarking,” but name the package
dpid_benchmarking
in pubspec.yaml
. The idea here is to save a few keystrokes on the directory name, but ensure that my local package names do not conflict with any that might need to be used as dependencies. So in packages/benchmarking
, I create a pubspec.yaml
for my local-only package:name: dpid_benchmarking dev_dependencies: args: any benchmark_harness: anyThere is nothing fancy there—it reads like any other package specification in Dart, which is nice.
The first bit of common code that I would like to pull in is not Dart. Rather it is the common
_benchmark.sh
Bash code from last night. There is nothing in Dart's packages that prevent packaging other languages, a fact that I exploit here:$ git mv visitor/tool/_benchmark.sh packages/benchmarking/libI use the
lib
subdirectory in the package because that is the only location that is readily shared by Dart packages.To use
_benchmark.sh
from the vistor
code samples, I now need to declare that it depends on my local-only package. This can be done in pubspec.yaml
with a dependency. Since this is benchmarking code, it is not a build dependency. Rather it is a development dependency. And, since this is a local-only package, I have to specify a path
attribute for my development dependency:name: visitor_code dev_dependencies: dpid_benchmarking: path: ../packages/benchmarkingI suffer a single relative path in my
pubspec.yaml
because Pub rewards me with a common, non-relative path after pub install
. Installing this local-only package creates a symbolic link to packages/dpid_benchmarking/lib
in the packages directory:$ pwd /home/chris/repos/design-patterns-in-dart/visitor $ ls -l packages lrwxrwxrwx 1 chris chris 31 Jul 22 21:35 dpid_benchmarking -> ../../packages/benchmarking/lib lrwxrwxrwx 1 chris chris 6 Jul 22 21:35 visitor_code -> ../libEspecially useful here is that Dart Pub creates this
packages
directory in all of the standard pub subdirectories like tool
:$ cd tool $ pwd /home/chris/repos/design-patterns-in-dart/visitor/tool $ ls -l packages/ lrwxrwxrwx 1 chris chris 31 Jul 22 21:35 dpid_benchmarking -> ../../packages/benchmarking/lib lrwxrwxrwx 1 chris chris 6 Jul 22 21:35 visitor_code -> ../libThis is wonderfully useful in my visitor pattern's
benchmark.sh
Bash script. Instead of sourcing _benchmark.sh
in the current tool
directory, I simply change it so that it sources it from the local-only package:#!/bin/bash source ./packages/dpid_benchmarking/_benchmark.sh BENCHMARK_SCRIPTS=( tool/benchmark.dart tool/benchmark_single_dispatch_iteration.dart tool/benchmark_visitor_traverse.dart ) _run_benchmarks $1The symbolic links from Dart Pub takes care of the rest. Nice!
Of course, Pub is the Dart package manager, so it works with Dart code as well. I move some obvious candidates for common benchmarking from
visitor/tool/src
into the local-only package:$ git mv visitor/tool/src/config.dart packages/benchmarking/lib/ $ git mv visitor/tool/src/score_emitters.dart packages/benchmarking/lib/It is then a simple matter of changing the import statements to use the local-only package:
import 'package:dpid_benchmarking/config.dart'; import 'package:dpid_benchmarking/score_emitters.dart'; import 'package:visitor_code/visitor.dart'; main (ListDart takes care of the rest!args) { // ... }
Best of all, I rinse and repeat in the rest of my design patterns. I add the
dpid_benchmarking
local-only package as a development dependency, run pub install
, then make use of this common code to ensure that I have beautiful data to back up some beautiful design patterns.That is an all-around win thanks to Dart's Pub package manager. Yay!
Day #130
No comments:
Post a Comment