Change option names and improve POD
[rails.git] / script / locale / diff
1 #!/usr/bin/env perl
2 use strict;
3 use warnings;
4 use YAML::Syck qw(LoadFile);
5 use Test::Differences;
6 use Pod::Usage ();
7 use Getopt::Long ();
8
9 =head1 NAME
10
11 locale-diff - Compare two YAML files and print how their datastructures differ
12
13 =head1 SYNOPSIS
14
15     diff en.yml is.yml
16     # --keys is the default
17     diff --keys en.yml is.yml
18     # --untranslated-values compares prints keys whose values don't differ
19     diff --untranslated-values en.yml is.yml
20
21 =head1 DESCRIPTION
22
23 This utility prints the differences between two YAML files using
24 L<Test::Differences>. The purpose of it is to diff the files is
25 F<config/locales> to find out what keys need to be added to the
26 translated files when F<en.yml> changes.
27
28 =head1 OPTIONS
29
30 =over
31
32 =item -h, --help
33
34 Print this help message.
35
36 =item --keys
37
38 Show the hash keys that differ between the two files, useful merging
39 new entries from F<en.yml> to a local file.
40
41 =item --untranslated-values
42
43 Show keys whose values are either exactly the same between the two
44 files, or don't exist in the target file (the latter file specified).
45
46 This helps to find untranslated values.
47
48 =back
49
50 =head1 AUTHOR
51
52 E<AElig>var ArnfjE<ouml>rE<eth> Bjarmason <avar@f-prot.com>
53
54 =cut
55
56 # Get the command-line options
57 Getopt::Long::Parser->new(
58     config => [ qw< bundling no_ignore_case no_require_order pass_through > ],
59 )->getoptions(
60     'h|help' => \my $help,
61     'keys' => \my $keys,
62     'untranslated-values' => \my $untranslated_values,
63 ) or help();
64
65 # On --help
66 help() if $help;
67
68 # If we're not given two .yml files
69 help() if @ARGV != 2 or (!-f $ARGV[0] or !-f $ARGV[1]);
70
71 my ($from, $to) = @ARGV;
72
73 my $from_data = LoadFile($from);
74 my $to_data   = LoadFile($to);
75
76 my $from_parsed = { iterate($from_data->{basename($from)}) };
77 my $to_parsed = { iterate($to_data->{basename($to)}) };
78
79 # Since this used to be the default, support that...
80 if ((not $untranslated_values and not $keys) or $keys)
81 {
82     print_key_differences();
83 }
84 elsif ($untranslated_values)
85 {
86     my @untranslated = untranslated_keys($from_parsed, $to_parsed);
87
88     print $_, "\n" for @untranslated;
89 }
90
91 exit 0;
92
93 sub print_key_differences
94 {
95     # Hack around Test::Differences wanting a Test::* module loaded
96     $INC{"Test.pm"} = 1;
97     sub Test::ok { print shift }
98
99     # Diff the tree
100     eq_or_diff([ sort keys %$from_parsed ], [ sort keys %$to_parsed ]);
101 }
102
103 sub untranslated_keys
104 {
105     my ($from_parsed, $to_parsed) = @_;
106     sort grep { not exists $to_parsed->{$_} or $from_parsed->{$_} eq $to_parsed->{$_} } keys %$from_parsed;
107 }
108
109 sub iterate
110 {
111     my ($hash, @path) = @_;
112     my @ret;
113         
114     while (my ($k, $v) = each %$hash)
115     {
116         if (ref $v eq 'HASH')
117         {
118              push @ret => iterate($v, @path, $k);
119         }
120         else
121         {
122             push @ret => join(".",@path, $k), $v;
123         }
124     }
125
126     return @ret;
127 }
128
129 sub basename
130 {
131     my $name = shift;
132     $name =~ s[\..*?$][];
133     $name;
134 }
135
136 sub help
137 {
138     my %arg = @_;
139
140     Pod::Usage::pod2usage(
141         -verbose => $arg{ verbose },
142         -exitval => $arg{ exitval } || 0,
143     );
144 }