ul-wukong 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +60 -0
- data/.gitmodules +6 -0
- data/.rspec +2 -0
- data/.travis.yml +19 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +17 -0
- data/Guardfile +12 -0
- data/LICENSE.md +95 -0
- data/NOTES-travis.md +31 -0
- data/README-old.md +422 -0
- data/README.md +1308 -0
- data/Rakefile +28 -0
- data/TODO.md +99 -0
- data/bin/cutc +30 -0
- data/bin/cuttab +5 -0
- data/bin/greptrue +6 -0
- data/bin/md5sort +20 -0
- data/bin/setcat +11 -0
- data/bin/tabchar +5 -0
- data/bin/uniq-ord +59 -0
- data/bin/uniqc +3 -0
- data/bin/wu +34 -0
- data/bin/wu-clean-encoding +31 -0
- data/bin/wu-date +13 -0
- data/bin/wu-datetime +13 -0
- data/bin/wu-hist +3 -0
- data/bin/wu-lign +186 -0
- data/bin/wu-local +4 -0
- data/bin/wu-plus +9 -0
- data/bin/wu-source +5 -0
- data/bin/wu-sum +31 -0
- data/diagrams/wu_local.dot +39 -0
- data/diagrams/wu_local.dot.png +0 -0
- data/examples/Gemfile +38 -0
- data/examples/README.md +9 -0
- data/examples/basic/string_reverser.rb +23 -0
- data/examples/basic/tiny_count.rb +8 -0
- data/examples/basic/word_count/accumulator.rb +26 -0
- data/examples/basic/word_count/tokenizer.rb +13 -0
- data/examples/basic/word_count/word_count.rb +6 -0
- data/examples/dataflow/scraper_macro_flow.rb +28 -0
- data/examples/deploy_pack/Gemfile +6 -0
- data/examples/deploy_pack/README.md +6 -0
- data/examples/deploy_pack/a/b/c/.gitkeep +0 -0
- data/examples/deploy_pack/app/processors/string_reverser.rb +5 -0
- data/examples/deploy_pack/config/environment.rb +1 -0
- data/examples/dsl/dataflow/fibonacci_series.rb +101 -0
- data/examples/dsl/dataflow/scraper_macro_flow.rb +28 -0
- data/examples/dsl/dataflow/simple.rb +12 -0
- data/examples/dsl/dataflow/telegram.rb +45 -0
- data/examples/dsl/workflow/cherry_pie.dot +97 -0
- data/examples/dsl/workflow/cherry_pie.md +104 -0
- data/examples/dsl/workflow/cherry_pie.png +0 -0
- data/examples/dsl/workflow/cherry_pie.rb +101 -0
- data/examples/empty/.gitkeep +0 -0
- data/examples/examples_helper.rb +9 -0
- data/examples/geo.rb +4 -0
- data/examples/geo/geo_grids.numbers +0 -0
- data/examples/geo/geolocated.rb +331 -0
- data/examples/geo/quadtile.rb +69 -0
- data/examples/geo/spec/geolocated_spec.rb +247 -0
- data/examples/geo/tile_fetcher.rb +77 -0
- data/examples/graph/implied_geolocation/README.md +63 -0
- data/examples/graph/minimum_spanning_tree/airfares_graphviz.rb +73 -0
- data/examples/improver/tweet_summary.rb +73 -0
- data/examples/loadable.rb +2 -0
- data/examples/munging/airline_flights/airline_flights.rake +83 -0
- data/examples/munging/airline_flights/airplane.rb +0 -0
- data/examples/munging/airline_flights/airport_id_unification.rb +129 -0
- data/examples/munging/airline_flights/airport_ok_chars.rb +4 -0
- data/examples/munging/airline_flights/indexable.rb +75 -0
- data/examples/munging/airline_flights/indexable_spec.rb +90 -0
- data/examples/munging/airline_flights/reconcile_airports.rb +142 -0
- data/examples/munging/airline_flights/tasks.rake +83 -0
- data/examples/munging/airline_flights/topcities.rb +167 -0
- data/examples/munging/geo/geo_json.rb +54 -0
- data/examples/munging/geo/geo_models.rb +69 -0
- data/examples/munging/geo/geonames_models.rb +107 -0
- data/examples/munging/geo/iso_codes.rb +172 -0
- data/examples/munging/geo/reconcile_countries.rb +124 -0
- data/examples/munging/geo/tasks.rake +71 -0
- data/examples/munging/wikipedia/articles/extract_articles-parsed.rb +79 -0
- data/examples/munging/wikipedia/articles/extract_articles-templated.rb +136 -0
- data/examples/munging/wikipedia/articles/textualize_articles.rb +54 -0
- data/examples/munging/wikipedia/articles/verify_structure.rb +43 -0
- data/examples/munging/wikipedia/articles/wp2txt-LICENSE.txt +22 -0
- data/examples/munging/wikipedia/articles/wp2txt_article.rb +259 -0
- data/examples/munging/wikipedia/articles/wp2txt_utils.rb +452 -0
- data/examples/munging/wikipedia/dbpedia/dbpedia_common.rb +5 -0
- data/examples/munging/wikipedia/dbpedia/dbpedia_extract_geocoordinates.rb +78 -0
- data/examples/munging/wikipedia/dbpedia/extract_links-cruft.rb +66 -0
- data/examples/munging/wikipedia/dbpedia/extract_links.rb +260 -0
- data/examples/munging/wikipedia/dbpedia/sameas_extractor.rb +20 -0
- data/examples/rake_helper.rb +97 -0
- data/examples/ruby_project/Gemfile +6 -0
- data/examples/ruby_project/README.md +6 -0
- data/examples/ruby_project/a/b/c/.gitkeep +0 -0
- data/examples/server_logs/geo_ip_mapping/munge_geolite.rb +82 -0
- data/examples/server_logs/logline.rb +95 -0
- data/examples/server_logs/models.rb +66 -0
- data/examples/server_logs/page_counts.pig +48 -0
- data/examples/server_logs/server_logs-01-parse-script.rb +13 -0
- data/examples/server_logs/server_logs-02-histograms-full.rb +33 -0
- data/examples/server_logs/server_logs-02-histograms-mapper.rb +14 -0
- data/examples/server_logs/server_logs-03-breadcrumbs-full.rb +71 -0
- data/examples/server_logs/server_logs-04-page_page_edges-full.rb +40 -0
- data/examples/serverlogs/geo_ip_mapping/munge_geolite.rb +82 -0
- data/examples/serverlogs/models/logline.rb +102 -0
- data/examples/serverlogs/parser/apache_parser_widget.rb +46 -0
- data/examples/serverlogs/visit_paths/common.rb +4 -0
- data/examples/serverlogs/visit_paths/page_counts.pig +48 -0
- data/examples/serverlogs/visit_paths/serverlogs-01-parse-script.rb +11 -0
- data/examples/serverlogs/visit_paths/serverlogs-02-histograms-full.rb +31 -0
- data/examples/serverlogs/visit_paths/serverlogs-02-histograms-mapper.rb +12 -0
- data/examples/serverlogs/visit_paths/serverlogs-03-breadcrumbs-full.rb +67 -0
- data/examples/serverlogs/visit_paths/serverlogs-04-page_page_edges-full.rb +38 -0
- data/examples/splitter.rb +94 -0
- data/examples/string_reverser.rb +7 -0
- data/examples/text/pig_latin/pig_latinizer.rb +35 -0
- data/examples/text/pig_latin/pig_latinizer_widget.rb +16 -0
- data/examples/text/regional_flavor/README.md +14 -0
- data/examples/text/regional_flavor/article_wordbags.pig +39 -0
- data/examples/text/regional_flavor/j01-article_wordbags.rb +4 -0
- data/examples/text/regional_flavor/simple_pig_script.pig +27 -0
- data/examples/twitter.rb +5 -0
- data/lib/hanuman.rb +36 -0
- data/lib/hanuman/graph.rb +97 -0
- data/lib/hanuman/graphvizzer.rb +206 -0
- data/lib/hanuman/graphvizzer/gv_models.rb +161 -0
- data/lib/hanuman/graphvizzer/gv_presenter.rb +97 -0
- data/lib/hanuman/link.rb +35 -0
- data/lib/hanuman/registry.rb +46 -0
- data/lib/hanuman/stage.rb +128 -0
- data/lib/hanuman/tree.rb +67 -0
- data/lib/wu/geo.rb +4 -0
- data/lib/wu/geo/geo_grids.numbers +0 -0
- data/lib/wu/geo/geolocated.rb +331 -0
- data/lib/wu/geo/quadtile.rb +69 -0
- data/lib/wu/graph/union_find.rb +62 -0
- data/lib/wu/model/reconcilable.rb +63 -0
- data/lib/wu/munging.rb +71 -0
- data/lib/wu/social/models/twitter.rb +31 -0
- data/lib/wu/wikipedia/models.rb +20 -0
- data/lib/wukong.rb +54 -0
- data/lib/wukong/dataflow.rb +43 -0
- data/lib/wukong/doc_helpers.rb +14 -0
- data/lib/wukong/doc_helpers/dataflow_handler.rb +29 -0
- data/lib/wukong/doc_helpers/field_handler.rb +91 -0
- data/lib/wukong/doc_helpers/processor_handler.rb +29 -0
- data/lib/wukong/driver.rb +214 -0
- data/lib/wukong/driver/event_machine_driver.rb +15 -0
- data/lib/wukong/driver/wiring.rb +68 -0
- data/lib/wukong/local.rb +42 -0
- data/lib/wukong/local/runner.rb +96 -0
- data/lib/wukong/local/stdio_driver.rb +104 -0
- data/lib/wukong/logger.rb +102 -0
- data/lib/wukong/model/faker.rb +136 -0
- data/lib/wukong/model/flatpack_parser/flat.rb +60 -0
- data/lib/wukong/model/flatpack_parser/flatpack.rb +4 -0
- data/lib/wukong/model/flatpack_parser/lang.rb +46 -0
- data/lib/wukong/model/flatpack_parser/parser.rb +55 -0
- data/lib/wukong/model/flatpack_parser/tokens.rb +130 -0
- data/lib/wukong/plugin.rb +48 -0
- data/lib/wukong/processor.rb +110 -0
- data/lib/wukong/rake_helper.rb +6 -0
- data/lib/wukong/runner.rb +169 -0
- data/lib/wukong/runner/boot_sequence.rb +123 -0
- data/lib/wukong/runner/code_loader.rb +52 -0
- data/lib/wukong/runner/command_runner.rb +44 -0
- data/lib/wukong/runner/deploy_pack_loader.rb +75 -0
- data/lib/wukong/runner/help_message.rb +42 -0
- data/lib/wukong/source.rb +33 -0
- data/lib/wukong/source/source_driver.rb +74 -0
- data/lib/wukong/source/source_runner.rb +38 -0
- data/lib/wukong/spec_helpers.rb +74 -0
- data/lib/wukong/spec_helpers/integration_tests.rb +150 -0
- data/lib/wukong/spec_helpers/integration_tests/integration_test_matchers.rb +207 -0
- data/lib/wukong/spec_helpers/integration_tests/integration_test_runner.rb +97 -0
- data/lib/wukong/spec_helpers/shared_examples.rb +22 -0
- data/lib/wukong/spec_helpers/unit_tests.rb +135 -0
- data/lib/wukong/spec_helpers/unit_tests/unit_test_driver.rb +132 -0
- data/lib/wukong/spec_helpers/unit_tests/unit_test_matchers.rb +169 -0
- data/lib/wukong/spec_helpers/unit_tests/unit_test_runner.rb +60 -0
- data/lib/wukong/version.rb +3 -0
- data/lib/wukong/widget/echo.rb +55 -0
- data/lib/wukong/widget/extract.rb +122 -0
- data/lib/wukong/widget/filters.rb +452 -0
- data/lib/wukong/widget/logger.rb +56 -0
- data/lib/wukong/widget/operators.rb +82 -0
- data/lib/wukong/widget/reducers.rb +10 -0
- data/lib/wukong/widget/reducers/accumulator.rb +73 -0
- data/lib/wukong/widget/reducers/bin.rb +368 -0
- data/lib/wukong/widget/reducers/count.rb +73 -0
- data/lib/wukong/widget/reducers/group.rb +128 -0
- data/lib/wukong/widget/reducers/group_concat.rb +98 -0
- data/lib/wukong/widget/reducers/improver.rb +71 -0
- data/lib/wukong/widget/reducers/join_xml.rb +37 -0
- data/lib/wukong/widget/reducers/moments.rb +72 -0
- data/lib/wukong/widget/reducers/sort.rb +180 -0
- data/lib/wukong/widget/reducers/uniq.rb +91 -0
- data/lib/wukong/widget/serializers.rb +317 -0
- data/lib/wukong/widget/utils.rb +46 -0
- data/lib/wukong/widgets.rb +7 -0
- data/spec/examples/dataflow/fibonacci_series_spec.rb +18 -0
- data/spec/examples/dataflow/parse_apache_logs_spec.rb +8 -0
- data/spec/examples/dataflow/parsing_spec.rb +14 -0
- data/spec/examples/dataflow/simple_spec.rb +34 -0
- data/spec/examples/dataflow/telegram_spec.rb +43 -0
- data/spec/examples/graph/minimum_spanning_tree_spec.rb +34 -0
- data/spec/examples/munging/airline_flights/identifiers_spec.rb +16 -0
- data/spec/examples/munging/airline_flights_spec.rb +202 -0
- data/spec/examples/text/pig_latin_spec.rb +18 -0
- data/spec/examples/workflow/cherry_pie_spec.rb +36 -0
- data/spec/hanuman/graph_spec.rb +119 -0
- data/spec/hanuman/hanuman_spec.rb +10 -0
- data/spec/hanuman/registry_spec.rb +123 -0
- data/spec/hanuman/stage_spec.rb +81 -0
- data/spec/hanuman/tree_spec.rb +119 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/support/example_test_helpers.rb +95 -0
- data/spec/support/hanuman_test_helpers.rb +92 -0
- data/spec/support/integration_helper.rb +38 -0
- data/spec/support/model_test_helpers.rb +115 -0
- data/spec/support/shared_context_for_graphs.rb +57 -0
- data/spec/support/shared_context_for_reducers.rb +37 -0
- data/spec/support/shared_examples_for_builders.rb +94 -0
- data/spec/support/shared_examples_for_shortcuts.rb +57 -0
- data/spec/wu/model/reconcilable_spec.rb +152 -0
- data/spec/wukong/dataflow_spec.rb +87 -0
- data/spec/wukong/driver_spec.rb +154 -0
- data/spec/wukong/local/runner_spec.rb +29 -0
- data/spec/wukong/local/stdio_driver_spec.rb +73 -0
- data/spec/wukong/local_spec.rb +6 -0
- data/spec/wukong/logger_spec.rb +49 -0
- data/spec/wukong/model/faker_spec.rb +132 -0
- data/spec/wukong/processor_spec.rb +21 -0
- data/spec/wukong/runner_spec.rb +132 -0
- data/spec/wukong/source_spec.rb +6 -0
- data/spec/wukong/widget/extract_spec.rb +101 -0
- data/spec/wukong/widget/filters_spec.rb +79 -0
- data/spec/wukong/widget/logger_spec.rb +23 -0
- data/spec/wukong/widget/operators_spec.rb +25 -0
- data/spec/wukong/widget/reducers/bin_spec.rb +92 -0
- data/spec/wukong/widget/reducers/count_spec.rb +11 -0
- data/spec/wukong/widget/reducers/group_spec.rb +21 -0
- data/spec/wukong/widget/reducers/join_xml_spec.rb +25 -0
- data/spec/wukong/widget/reducers/moments_spec.rb +36 -0
- data/spec/wukong/widget/reducers/sort_spec.rb +26 -0
- data/spec/wukong/widget/reducers/uniq_spec.rb +14 -0
- data/spec/wukong/widget/serializers_spec.rb +114 -0
- data/spec/wukong/widget/sink_spec.rb +19 -0
- data/spec/wukong/widget/source_spec.rb +65 -0
- data/spec/wukong/wu-local_spec.rb +109 -0
- data/spec/wukong/wu-source_spec.rb +32 -0
- data/spec/wukong/wu_spec.rb +14 -0
- data/spec/wukong/wukong_spec.rb +10 -0
- data/wukong.gemspec +35 -0
- metadata +465 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
module Wukong
|
2
|
+
module Local
|
3
|
+
|
4
|
+
# A class for driving processors over the STDIN/STDOUT protocol.
|
5
|
+
#
|
6
|
+
# Relies on EventMachine's [LineAndTextProtocol](http://eventmachine.rubyforge.org/EventMachine/Protocols/LineText2.html).
|
7
|
+
class StdioDriver < EM::P::LineAndTextProtocol
|
8
|
+
|
9
|
+
include DriverMethods
|
10
|
+
include Logging
|
11
|
+
|
12
|
+
#
|
13
|
+
# == Startup ==
|
14
|
+
#
|
15
|
+
|
16
|
+
# Start a new StdioDriver.
|
17
|
+
#
|
18
|
+
# @param [Symbol] the name of the processor or dataflow to drive
|
19
|
+
# @param [Configliere::Param] settings the settings to use
|
20
|
+
def self.start(label, settings = {})
|
21
|
+
EM.attach($stdin, self, label, settings)
|
22
|
+
end
|
23
|
+
|
24
|
+
# :nodoc:
|
25
|
+
def initialize(label, settings)
|
26
|
+
super
|
27
|
+
construct_dataflow(label, settings)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Ensures that $stdout is synced.
|
31
|
+
def setup()
|
32
|
+
$stdout.sync
|
33
|
+
end
|
34
|
+
|
35
|
+
# Adds signal traps for SIGINT and SIGTERM to Ensure we capture
|
36
|
+
# C-c and friends, stop the EventMachine reactor, &c.
|
37
|
+
def self.add_signal_traps
|
38
|
+
Signal.trap('INT') { log.info 'Received SIGINT. Stopping.' ; EM.stop }
|
39
|
+
Signal.trap('TERM') { log.info 'Received SIGTERM. Stopping.' ; EM.stop }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Called by EventMachine framework after successfully attaching
|
43
|
+
# to $stdin.
|
44
|
+
#
|
45
|
+
# Adds signal handlers and calls the #setup_dataflow method.
|
46
|
+
def post_init
|
47
|
+
self.class.add_signal_traps
|
48
|
+
setup_dataflow
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# == Reading Input ==
|
53
|
+
#
|
54
|
+
|
55
|
+
# Called by EventMachine framework after successfully reading a
|
56
|
+
# line from $stdin.
|
57
|
+
#
|
58
|
+
# @param [String] line
|
59
|
+
def receive_line line
|
60
|
+
send_through_dataflow(line)
|
61
|
+
rescue => e
|
62
|
+
error = Wukong::Error.new(e)
|
63
|
+
# EM.stop
|
64
|
+
|
65
|
+
# We'd like to *raise* `error` here and have it be handled by
|
66
|
+
# Wukong::Runner.run but we are fighting with EventMachine.run
|
67
|
+
# which executes in the middle.
|
68
|
+
#
|
69
|
+
# It seems no matter what we do, EventMachine.run will swallow
|
70
|
+
# any Exception raised here (including SystemExit) and exit
|
71
|
+
# the Ruby process with a return code of 0.
|
72
|
+
#
|
73
|
+
# Instead we just log the message that *would* have gotten
|
74
|
+
# logged by Wukong::Runner.run and leave it to EventMachine to
|
75
|
+
# exit very unnaturally.
|
76
|
+
log.error(error.message)
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# == Handling Output ==
|
81
|
+
#
|
82
|
+
|
83
|
+
# Writes a record to $stdout.
|
84
|
+
#
|
85
|
+
# @param [#to_s] record
|
86
|
+
def process(record)
|
87
|
+
$stdout.puts record
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# == Shutdown ==
|
92
|
+
#
|
93
|
+
|
94
|
+
# Called by EventMachine framework after EOF from $stdin.
|
95
|
+
#
|
96
|
+
# Calls #finalize_and_stop_dataflow method and stops the
|
97
|
+
# EventMachine reactor.
|
98
|
+
def unbind
|
99
|
+
finalize_and_stop_dataflow
|
100
|
+
EM.stop
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Wukong
|
2
|
+
|
3
|
+
class LogFactory
|
4
|
+
|
5
|
+
attr_reader :created_log
|
6
|
+
|
7
|
+
def self.default_outputter klass
|
8
|
+
Log4r::StderrOutputter.new('console', formatter: default_formatter(klass))
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.default_formatter klass
|
12
|
+
Log4r::PatternFormatter.new(pattern: default_pattern(klass))
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.default_pattern klass
|
16
|
+
"%l %d [%-20c] -- %m"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.configure(klass, options = {})
|
20
|
+
factory = new(klass, options)
|
21
|
+
factory.created_log
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(logger, config)
|
25
|
+
@created_log = logger.is_a?(Log4r::Logger) ? logger : Log4r::Logger.new(logger.to_s)
|
26
|
+
outputter(LogFactory.default_outputter(logger)) unless ancestry_has_outputter?(@created_log)
|
27
|
+
apply_options(config)
|
28
|
+
end
|
29
|
+
|
30
|
+
def ancestry_has_outputter? lgr
|
31
|
+
if lgr.respond_to?(:outputters) && !lgr.outputters.empty?
|
32
|
+
true
|
33
|
+
elsif lgr.respond_to?(:parent) && !lgr.parent.nil?
|
34
|
+
ancestry_has_outputter? lgr.parent
|
35
|
+
else
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def apply_options config
|
41
|
+
config.each_pair do |option, value|
|
42
|
+
begin
|
43
|
+
send(option, value)
|
44
|
+
rescue
|
45
|
+
raise Error.new("Error setting option <#{option}> to value <#{value}>")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def outputter outptr
|
51
|
+
created_log.outputters = outptr
|
52
|
+
end
|
53
|
+
|
54
|
+
def level lvl
|
55
|
+
created_log.level = lookup_level(lvl.to_sym)
|
56
|
+
end
|
57
|
+
|
58
|
+
def lookup_level lvl
|
59
|
+
{
|
60
|
+
debug: Log4r::DEBUG,
|
61
|
+
info: Log4r::INFO,
|
62
|
+
warn: Log4r::WARN
|
63
|
+
}.fetch(lvl){ raise Error.new("Invalid log level: <#{lvl}>") }
|
64
|
+
end
|
65
|
+
|
66
|
+
def pattern ptrn
|
67
|
+
created_log.outputters.each do |output|
|
68
|
+
keep_date_format = output.formatter.date_pattern
|
69
|
+
output.formatter = Log4r::PatternFormatter.new(pattern: ptrn, date_format: keep_date_format)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def date_format fmt
|
74
|
+
created_log.outputters.each do |output|
|
75
|
+
keep_pattern = output.formatter.pattern
|
76
|
+
output.formatter = Log4r::PatternFormatter.new(pattern: keep_pattern, date_format: fmt)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Mixin for logging behavior
|
82
|
+
module Logging
|
83
|
+
|
84
|
+
def self.included klass
|
85
|
+
if klass.ancestors.include?(Gorillib::Model)
|
86
|
+
klass.class_eval do
|
87
|
+
field(:log, Whatever, :default => ->{ Wukong::LogFactory.configure(self.class) }, :doc => "Shared Wukong logger")
|
88
|
+
|
89
|
+
def receive_log params
|
90
|
+
@log = LogFactory.configure(self.class, params)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
else
|
94
|
+
klass.class_attribute :log
|
95
|
+
klass.log = LogFactory.configure(klass)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Default log. Parent to all logs created in Wukong namespace
|
101
|
+
Log = LogFactory.configure(Wukong)
|
102
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'forgery'
|
2
|
+
require 'uuidtools'
|
3
|
+
|
4
|
+
# Bolt extra parameters onto field declaration
|
5
|
+
|
6
|
+
class Gorillib::Model::Field
|
7
|
+
field :faker, Whatever, :doc => "Factory for creating a fake value; anything responding to #fake_value()", :tester => true
|
8
|
+
field :faker_args, Array, :doc => "Parameters to splat in for calls to the faker factory", :default => []
|
9
|
+
|
10
|
+
def fake_value
|
11
|
+
faker = read_attribute(:faker)
|
12
|
+
case faker
|
13
|
+
when nil then self.type.fake_value(*faker_args)
|
14
|
+
when Symbol then Wukong::Faker::Helpers.public_send(faker, *faker_args)
|
15
|
+
when Proc, Method then faker.call(*faker_args)
|
16
|
+
else faker.fake_value(*faker_args)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Wukong
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
#
|
25
|
+
# class Person
|
26
|
+
# include Gorillib::Model
|
27
|
+
# include Wukong::Faker
|
28
|
+
# field :first_name, String, :faker => ->{ %w[John Paul George Ringo] }
|
29
|
+
# field :last_name, String
|
30
|
+
# field :user_id, String, :faker => :fake_identifier
|
31
|
+
#
|
32
|
+
module Faker
|
33
|
+
extend Gorillib::Concern
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
|
37
|
+
def fake_value
|
38
|
+
new.update_attributes(fake_attrs)
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
#
|
43
|
+
# For the example of a field `:foo` of type `HappyType`, calls the first of:
|
44
|
+
# * the instance method :fake_foo if it exists.
|
45
|
+
# * `fake_value` on the `:faker => XX` parameter in `:foo`'s field definition.
|
46
|
+
# * `fake_value` on the field's type
|
47
|
+
#
|
48
|
+
# If the faker is simple, or if there's a standard faker for what you want,
|
49
|
+
# When a generic faker won't do, or is complicated, use
|
50
|
+
def fake_attrs
|
51
|
+
attrs = {}
|
52
|
+
fields.each do |field_name, field|
|
53
|
+
attrs[field_name] = self.respond_to?("fake_#{field_name}") ? send("fake_#{field_name}") : field.fake_value
|
54
|
+
end
|
55
|
+
attrs
|
56
|
+
end
|
57
|
+
|
58
|
+
# defines a method to return an arbitrary value from the given list.
|
59
|
+
def fake_from_list(field_name, values)
|
60
|
+
define_singleton_method("fake_#{field_name}"){ values.sample }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module Helpers
|
65
|
+
extend self
|
66
|
+
|
67
|
+
def fake_integer(opts={})
|
68
|
+
opts = { :min => 0, :max => 1 }.merge(opts)
|
69
|
+
min, max = [ opts[:min].to_i, opts[:max].to_i ].sort
|
70
|
+
return min if min == max
|
71
|
+
min + Kernel.rand(max-min)
|
72
|
+
end
|
73
|
+
def fake_float(opts={})
|
74
|
+
opts = { :min => 0.0, :max => 1.0 }.merge(opts)
|
75
|
+
min, max = [ opts[:min].to_f, opts[:max].to_f ].sort
|
76
|
+
min + ((max-min) * Kernel.rand)
|
77
|
+
end
|
78
|
+
|
79
|
+
# A latitude unif. dist from San Diego lat 32 lng -117 to Maine lat 44 lng -68 -- sorry non-yanks
|
80
|
+
def fake_latitude(opts={}) ; fake_float({:min => 32.0, :max => 45.0}.merge(opts)) ; end
|
81
|
+
# A longitude unif. dist from San Diego lat 32 lng -117 to Maine lat 44 lng -68 -- sorry non-yanks
|
82
|
+
def fake_longitude(opts={}) ; fake_float({:min => -117.0, :max => -68.0}.merge(opts)) ; end
|
83
|
+
|
84
|
+
def fake_country_id() ; Forgery::Internet.cctld ; end # KLUDGE: uses tlds, not country codes
|
85
|
+
def fake_area_code() ; fake_integer(:min => 200, :max => 987) ; end
|
86
|
+
|
87
|
+
def fake_word() ; Forgery::LoremIpsum.word(:random => true) ; end
|
88
|
+
def fake_identifier() ; fake_word.downcase.gsub(/\W/,'_').gsub(/^[^a-z]/, 'a') ; end
|
89
|
+
def fake_sentence() ; Forgery::LoremIpsum.sentence(:random => true) ; end
|
90
|
+
def fake_paragraph() ; Forgery::LoremIpsum.paragraph(:random => true) ; end
|
91
|
+
|
92
|
+
def fake_fileext() ; %w[ rb html py sh com bat doc txt pdf xml exe app].sample ; end
|
93
|
+
def fake_basename() ; "#{fake_identifier}.#{fake_fileext}" ; end
|
94
|
+
def fake_dirname() ; File.join('/', * 3.times.map{ fake_identifier }) ; end
|
95
|
+
def fake_filename() ; File.join(fake_dirname, fake_basename) ; end
|
96
|
+
|
97
|
+
def fake_hostname() ; Forgery::Internet.domain_name ; end
|
98
|
+
def fake_ip_addresss() ; Forgery::Internet.ip_v4 ; end
|
99
|
+
def fake_version_number() ; "%.1f" % fake_float(:min => 0.2, :max => 9.4) ; end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
module Gorillib::Factory
|
106
|
+
class BaseFactory
|
107
|
+
def fake_value(opts={})
|
108
|
+
if not @faker_warned then warn "No faker for #{self}" ; @faker_warned = true ; end
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
StringFactory.class_eval { def fake_value() receive(Wukong::Faker::Helpers.fake_word) ; end }
|
114
|
+
GuidFactory.class_eval { def fake_value() receive(UUIDTools::UUID.random_create.to_s) ; end }
|
115
|
+
HostnameFactory.class_eval { def fake_value() receive(Wukong::Faker::Helpers.fake_hostname) ; end }
|
116
|
+
IpAddressFactory.class_eval{ def fake_value() receive(Wukong::Faker::Helpers.fake_ip_addresss) ; end }
|
117
|
+
|
118
|
+
SymbolFactory.class_eval { def fake_value() receive(Wukong::Faker::Helpers.fake_identifier) ; end }
|
119
|
+
PathnameFactory.class_eval { def fake_value() receive(Wukong::Faker::Helpers.fake_filename) ; end }
|
120
|
+
|
121
|
+
IntegerFactory.class_eval { def fake_value(opts={}) receive(Wukong::Faker::Helpers.fake_integer(opts)) ; end }
|
122
|
+
BignumFactory.class_eval { def fake_value(opts={}) super({:min => 2**68, :max => 2**90}.merge(opts)) ; end }
|
123
|
+
|
124
|
+
FloatFactory.class_eval { def fake_value(opts={}) receive(Wukong::Faker::Helpers.fake_float(opts)) ; end }
|
125
|
+
ComplexFactory.class_eval { def fake_value() receive(Kernel.rand, Kernel.rand) ; end }
|
126
|
+
RationalFactory.class_eval { def fake_value() receive(Kernel.rand.to_r) ; end }
|
127
|
+
|
128
|
+
TimeFactory.class_eval { def fake_value() receive(Time.now) ; end }
|
129
|
+
|
130
|
+
ExceptionFactory.class_eval{ def fake_value() Exception.constants.sample ; end }
|
131
|
+
|
132
|
+
NilFactory.class_eval { def fake_value() nil ; end }
|
133
|
+
TrueFactory.class_eval { def fake_value() true ; end }
|
134
|
+
FalseFactory.class_eval { def fake_value() false ; end }
|
135
|
+
BooleanFactory.class_eval { def fake_value() [true, false].sample ; end }
|
136
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class String
|
2
|
+
def match_all regex
|
3
|
+
self.to_enum(:scan, regex).map {Regexp.last_match}
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
module Wukong
|
8
|
+
module FlatPack
|
9
|
+
|
10
|
+
# Creates a 'simple' token from the supplied string
|
11
|
+
# and position.
|
12
|
+
def self.simple_token_from_string(str, position)
|
13
|
+
token_pieces = str.match(Language::NAMED_SIMPLE_TYPE_RE)
|
14
|
+
t = Flat::Tokens.token_for_indicator(token_pieces[:type])
|
15
|
+
t.position = position
|
16
|
+
t.length = token_pieces[:length].nil? ? nil : token_pieces[:length].to_i
|
17
|
+
t.modifier = token_pieces[:modifier]
|
18
|
+
return t
|
19
|
+
end
|
20
|
+
|
21
|
+
# Creates a fixed point token. Strict input formatting is
|
22
|
+
# enforced if the strict param is true.
|
23
|
+
def self.fixed_point_token_from_string(str, position, strict=true)
|
24
|
+
float_pieces = str.match(Language::NAMED_FIXED_POINT_RE)
|
25
|
+
t = Flat::Tokens::FixedPointToken.new
|
26
|
+
t.position = position
|
27
|
+
t.strict = strict
|
28
|
+
t.power = float_pieces[:power].nil? ? nil : float_pieces[:power].to_i
|
29
|
+
t.length = float_pieces[:length].to_i
|
30
|
+
return t
|
31
|
+
end
|
32
|
+
|
33
|
+
# Validates the supplied format string
|
34
|
+
# and creates a parser from it.
|
35
|
+
def self.create_parser(str, delimiter_width=0, strict_fixed_point=true)
|
36
|
+
return nil unless Language.string_in_lang str
|
37
|
+
lang = []
|
38
|
+
str.match_all(Language::CAPTURE_TOKEN_RE).each do |match|
|
39
|
+
token_str = match[0]
|
40
|
+
case token_str
|
41
|
+
when Language::TOTAL_SIMPLE_TYPE_RE
|
42
|
+
lang << simple_token_from_string(token_str, match.begin(0))
|
43
|
+
when Language::TOTAL_FIXED_POINT_RE
|
44
|
+
lang << fixed_point_token_from_string(token_str, match.begin(0), strict_fixed_point)
|
45
|
+
when Language::TOTAL_DATE_RE
|
46
|
+
date_match = token_str.match(Language::NAMED_DATE_RE)
|
47
|
+
#TODO: Implement
|
48
|
+
end
|
49
|
+
if delimiter_width != 0
|
50
|
+
t = Flat::Tokens::IgnoreToken.new
|
51
|
+
t.position = -1
|
52
|
+
t.length = delimiter_width
|
53
|
+
lang << t
|
54
|
+
end
|
55
|
+
end
|
56
|
+
lang = lang[0..-2] if delimiter_width != 0 #pop off the delimiter on the end
|
57
|
+
return Flat::Parser.new(lang)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Wukong
|
2
|
+
module FlatPack
|
3
|
+
module Language
|
4
|
+
|
5
|
+
#language definition
|
6
|
+
SIMPLE_TYPES = %w{i f s b _}
|
7
|
+
SIMPLE_TYPE_RE = "[#{SIMPLE_TYPES.join}]"
|
8
|
+
|
9
|
+
MODIFIERS = %w{+ *}
|
10
|
+
MODIFIER_RE = "[#{MODIFIERS.join}]"
|
11
|
+
|
12
|
+
SIMPLE_TOKEN_RE = "#{SIMPLE_TYPE_RE}(?:#{MODIFIER_RE}|[0-9]+)?"
|
13
|
+
|
14
|
+
DATE_TYPES = %w{a A b B c d H I j m M p S U w W x X Y Z}
|
15
|
+
DATE_TYPES_RE = "[#{DATE_TYPES.join} ]" # the extra space is supposed to be there
|
16
|
+
DATE_TOKEN_RE = "%#{DATE_TYPES_RE}*%"
|
17
|
+
|
18
|
+
FIXED_POINT_TYPE = 'D'
|
19
|
+
FIXED_POINT_SEP = 'e'
|
20
|
+
FIXED_POINT_TOKEN_RE = "#{FIXED_POINT_TYPE}\\d+(?:#{FIXED_POINT_SEP}\\d+)?"
|
21
|
+
|
22
|
+
TOKENS = [SIMPLE_TOKEN_RE, DATE_TOKEN_RE, FIXED_POINT_TOKEN_RE]
|
23
|
+
TOKEN_RE = "#{TOKENS.join('|')}"
|
24
|
+
CAPTURE_TOKEN_RE = /(#{TOKENS.join('|')})/
|
25
|
+
|
26
|
+
LANGUAGE_RE = /^(?:(#{TOKEN_RE}) *)+$/
|
27
|
+
|
28
|
+
#total regexes, i.e. regexes that must match the whole string
|
29
|
+
TOTAL_SIMPLE_TYPE_RE = /^#{SIMPLE_TOKEN_RE}$/
|
30
|
+
TOTAL_FIXED_POINT_RE = /^#{FIXED_POINT_TOKEN_RE}$/
|
31
|
+
TOTAL_DATE_RE = /^#{DATE_TOKEN_RE}$/
|
32
|
+
|
33
|
+
#named regexes used for parsing tokens
|
34
|
+
NAMED_SIMPLE_TYPE_RE = /(?<type>#{SIMPLE_TYPE_RE})(?:(?<length>[0-9]+)|(?<modifier>#{MODIFIER_RE}))?/
|
35
|
+
NAMED_FIXED_POINT_RE = /#{FIXED_POINT_TYPE}(?<length>\d+)(?:#{FIXED_POINT_SEP}(?<power>\d+))?/
|
36
|
+
NAMED_DATE_RE = /%(?<format>#{DATE_TYPES_RE})%/
|
37
|
+
|
38
|
+
# Returns true if the supplied string is in
|
39
|
+
# Flat's formatting language, as determined
|
40
|
+
# by the LANGUAGE_RE regex.
|
41
|
+
def self.string_in_lang(str)
|
42
|
+
return (not (str =~ LANGUAGE_RE).nil?)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|