官术网_书友最值得收藏!

The command-line app for source code statistics

Our customers like the software development angle of the text editor and has asked for some source code statistics such as SLOC (source lines of code) to be made accessible. This feature may be of use outside the web page, such as in a continuous integration environment, so we will construct our first command-line application.

We will create the project in WebStorm from scratch, but a completed version is also supplied in the sample code in a folder called dart_stats.

The command-line project structure

Open WebStorm, click on Create New Project, and select Console application from the Project Templates list. Choose a location for your project and call it dart_stats.

The structure of the application has a bin folder with main.dart, which is the entry point for the application. This is where the main function is located. The project template contains several other items. For this tool, the focus will be on the main function.

Tip

Dart is cross-platform, and the majority of filesystems used by the OS platforms are case-sensitive. It is a highly-recommended convention that all filenames are lowercase.

Add the source code file sourcescan.dart to the project. This contains the code for scanning the text and tallying up line counts for classes, code, comments, imports, and whitespace.

Processing the source code

The SourceCodeScanner class contains five integer fields to store the counts and a single method to perform the analysis:

void scan: (List<String> lines) {
    totalLines = lines.length;
    lines.forEach((line) {
      line = line.trim();
      if (line.startsWith("class")) classes++;
      else if (line.startsWith("import")) imports++;
      else if (line.startsWith("http://")) comments++;
      else if (line.length == 0) whitespace++;
    });
  }

The list of lines is iterated over and the trim method is used to remove extra whitespace from the lines to aid in matching the keywords that trigger and increment the count. The startsWith method makes sure that the keyword is not appearing mid-line in another context.

File handling with the dart:io package

The application will be passed a single command-line argument, which is the full file path to a Dart source code file. The command-line arguments can be read from the parameter passed to the main function in main.dart.

One aspect that we will not have to deal with in the browser is loading the source code from a text file. A package that is not available to Dart in the web browser, due to security, is the IO package, which contains direct file handling functionality:

import 'sourcescan.dart';
import 'dart:io';

main(List<String> arguments) {
  print(arguments[0]);
  SourceCodeScanner codeScan = new SourceCodeScanner();
  File myFile = new File(arguments[0]);
  myFile.readAsLines().then((List<String> Lines) {
    codeScan.scan(Lines);
    print("${codeScan.totalLines}");
    print("${codeScan.classes}");
    print("${codeScan.comments}");
    print("${codeScan.imports}");
    print("${codeScan.whitespace}");
  });
}

Once the text file is in a string, it can be processed in the same manner as in the web text editor.

The program can be run from the command-line, as shown here on Linux:

$ dart bin/main.dart  lib/dartstats.dart
lib/dartstats.dart
9
0
3
0
2

The program can examine its own source code!

Tip

For more advanced handling of command-line arguments, see the very powerful args package on pub at https://pub.dartlang.org/packages/args.

readAsLines is an asynchronous function that immediately returns a Future object. A function is passed into the future object's then method. The timing of the execution of this function is unknown to the developer. The flow of the program continues straight away. When the file read operation is run and has completed, the function passed to the then method is executed when the Dart VM schedules it.

To see this in action, move the print statements outside of the then function, as shown, and run the program again:

...
  myFile.readAsLines().then((List<String> Lines) {
    codeScan.scan(Lines);
  });
  print("${codeScan.totalLines}");
  print("${codeScan.classes}");
  print("${codeScan.comments}");
  print("${codeScan.imports}");
  print("${codeScan.whitespace}");
...

The probable output is all zeros as the code lines have not been scanned yet; this is because the print functions are being called first.

It is also possible that the program will run just as before. The key point is that the overall program execution keeps moving forward even when the code is asked to perform a potentially long-running task, allowing other tasks to continue and keeping the application responsive.

Debugging the command-line program

If you launch the program as it is in WebStorm by using Run, then it will open up the debugger with a RangeError exception. This is because the program is assuming that a command-line argument has been passed and the program has been run without any input.

In WebStorm, launches of programs into debugging can be configured, including a feature to set command-line arguments. In this case, a full file path to a Dart source file should be put in the Program arguments field. Note that, by default, no command-line arguments are passed. It is also possible to set multiple launches with different sets of command-line options:

Debugging the command-line program

To configure launches, select the Edit Configurations option from the Run menu. Select main.dart from the list and enter the full file path of any Dart source code file, such as one for the sample code for this book or from the Dart SDK.

Once the program is run, the results are printed to standard output using the print function.

Integrating the statistics

The class SourceStats can be added to the text editor project by adding the sourcescan.dart file to the bin folder and referencing it as a straightforward import. The scan is to be performed on the contents of the editor in the scanCode method of the CodeStatDialog, and the data is to be extracted for drawing on the pie chart.

HTML5 and the canvas

Given that the Canvas HTML element has been around for approximately 10 years since Apple introduced it into their version of Webkit, it seems odd that it is still considered a new feature! Widespread support has been seen in the major and minor browsers for several years now.

The canvas element provides a high-performance 2D raster-based graphics bitmap that can be scripted dynamically. In contrast to SVG, there are no scene graphs or selectable objects, just a graphic image. It provides an easy-to-use and powerful way to display dynamic images on the client side for applications such as graphs, animations, and games:

HTML5 and the canvas

Drawing the pie chart

The four pieces of data collected are to be represented as segments in a pie chart. In the CodeStatsDialog constructor, the canvas HTML element is selected in the same manner as any other page element. A 2D context is requested, which returns an object we can call methods on to draw on the Canvas:

    CanvasElement graphs = new CanvasElement();
    graphs.width = 500;
    graphs.height = 270;
    c2d = graphs.getContext("2d");
    contentDiv..append(new BRElement())..append(graphs);

The stroke is the pen to be used and the fill is analogous to the paint. Each pie segment is drawn in a black outline (stroke) and painted in with the fill:

    for (int i = 0; i < 4; i++) {
      c2d
        ..fillStyle = colors[i]
        ..strokeStyle = "black"
        ..beginPath()
        ..moveTo(radius, radius)
        ..arc(radius, radius, radius, lastpos,
            (lastpos + (PI * 2.0 * (data[i] / totalLines))), false)
        ..lineTo(radius, radius)
        ..fill()
        ..stroke()
        ..closePath();
      lastpos += PI * 2.0 * (data[i] / totalLines);
      print(lastpos);

The arc method uses radians, so the constant PI is used in the calculations:

      c2d
        ..beginPath()
        ..strokeStyle = "black"
        ..fillStyle = colors[i]
        ..fillRect(380, 90 + 20 * i, 8, 8)
        ..strokeRect(380, 90 + 20 * i, 8, 8)
        ..strokeText(labels[i], 400, 100 + 20 * i)
        ..stroke()
        ..closePath();

The labels are drawn for each of the four counts by using a square Rect to show the color, and the text is drawn alongside it.

Note

The canvas is a versatile feature, but it can be frustrating when nothing appears on it. This often occurs when beginPath is used and the path has not been closed with closePath.

主站蜘蛛池模板: 都安| 称多县| 瑞安市| 肃南| 历史| 左云县| 东至县| 威海市| 广东省| 云南省| 福泉市| 论坛| 中牟县| 彰化县| 津南区| 通道| 通道| 百色市| 安福县| 卓尼县| 平阴县| 沙田区| 会同县| 宣化县| 梁山县| 麻栗坡县| 年辖:市辖区| 望都县| 资中县| 庆城县| 丰台区| 营口市| 思茅市| 陇南市| 鄯善县| 彩票| 常州市| 荆州市| 罗定市| 华宁县| 维西|