flog 1.2.0 → 2.0.0

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.
@@ -0,0 +1,11 @@
1
+ module Centerstone #:nodoc:
2
+ module AssociationExtensions
3
+ module DateRanged
4
+
5
+ def current
6
+ containing(Time.now)
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Centerstone #:nodoc:
2
+ module AssociationExtensions
3
+ module Ranged
4
+
5
+ %w{before after containing contained_by overlapping}.each do |comparison|
6
+ define_method comparison do |target|
7
+ self.select { |x| x.send((comparison + '?').to_sym, target) }
8
+ end
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,50 @@
1
+ module Centerstone #:nodoc:
2
+ module ReflectionExtensions
3
+ module Ranged
4
+
5
+ def self.included(base)
6
+ puts 'hello'
7
+ base.send(:include, InstanceMethods)
8
+
9
+ base.instance_eval do
10
+ alias_method_chain :initialize, :has_many_range_extension
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+ def initialize_with_has_many_range_extension(*args)
16
+ puts 'yo'
17
+ returning initialize_without_has_many_range_extension(*args) do
18
+ puts 'returning stuff'
19
+ if macro.to_s == 'has_many'
20
+ puts 'adding the extension'
21
+ add_has_many_range_extension
22
+ end
23
+ puts 'blah'
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def add_has_many_range_extension
30
+ puts 'extension adding, hey'
31
+ puts 'bbbbb'
32
+ puts "target class [#{klass}]"
33
+ if klass.acts_as_range?
34
+ puts 'target acts as range'
35
+ extension = Centerstone::AssociationExtensions::Ranged
36
+ opts = options
37
+
38
+ opts[:extend] ||= []
39
+ opts[:extend] = [opts[:extend]].flatten
40
+
41
+ opts[:extend].push(extension) unless opts[:extend].include?(extension)
42
+
43
+ @options = opts
44
+ end
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,70 @@
1
+ class BotFilter
2
+ attr_reader :options
3
+
4
+ def initialize(options = {})
5
+ @options = options
6
+ end
7
+
8
+ @@kinds = []
9
+ @@filters_registered = false
10
+
11
+ class << self
12
+ def new(options = {})
13
+ locate_filters(options) unless @@filters_registered
14
+ obj = allocate
15
+ obj.send :initialize, options
16
+ obj
17
+ end
18
+
19
+ def kinds
20
+ @@kinds
21
+ end
22
+
23
+ def register(name)
24
+ @@kinds << name
25
+ end
26
+
27
+ def clear_kinds
28
+ @@kinds = []
29
+ @@filters_registered = false
30
+ end
31
+
32
+ def get(ident)
33
+ name = ident.to_s.gsub(/(?:^|_)([a-z])/) { $1.upcase }.to_sym
34
+ const_get(name)
35
+ end
36
+
37
+ def locate_filters(options)
38
+ if options and options[:active_filters]
39
+ options[:active_filters].each do |filter|
40
+ register_filter(filter)
41
+ end
42
+ end
43
+ @@filters_registered = true
44
+ end
45
+
46
+ def filter_path(name)
47
+ File.expand_path(File.dirname(__FILE__)+"/../lib/filters/#{name}.rb")
48
+ end
49
+
50
+ def register_filter(name)
51
+ path = filter_path(name)
52
+ raise ArgumentError, "Could not find source code for filter [#{name}] in [#{path}]" unless File.exists? path
53
+ load(path)
54
+ register(name)
55
+ end
56
+ end
57
+
58
+ def process(data)
59
+ result = data
60
+ self.class.kinds.each do |k|
61
+ if result
62
+ result = BotFilter.get(k).new(options).process(result)
63
+ else
64
+ result = nil
65
+ break
66
+ end
67
+ end
68
+ result
69
+ end
70
+ end
@@ -0,0 +1,79 @@
1
+ require 'bot_parser_format'
2
+
3
+ class BotParser
4
+ @formats = []
5
+
6
+ class << self
7
+ attr_reader :formats
8
+
9
+ def register_format(*args, &block)
10
+ formats << BotParserFormat.new(*args, &block)
11
+ end
12
+
13
+ def clear_formats
14
+ @formats = []
15
+ end
16
+ end
17
+
18
+ def formats() self.class.formats; end
19
+
20
+ register_format :image, /^\s*(?:(.*?)\s+)?(http:\S+\.(?:jpe?g|png|gif))(?:\s+(\S.*))?$/i,
21
+ %q['http://www.citizenx.cx/img/best_picture_ever.jpg'],
22
+ %q['http://www.citizenx.cx/img/best_picture_never.jpg this poster hangs over my bed'],
23
+ %q['Best. Picture. Ever. http://www.citizenx.cx/img/best_picture_ever.jpg'] do |md, _|
24
+ { :title => md[1], :source => md[2], :caption => md[3] }
25
+ end
26
+
27
+ register_format :video, %r{^\s*(?:(.*?)\s+)?(http://(?:www\.)?youtube\.com/\S+\?\S+)(?:\s+(.*))?$}i,
28
+ %q['http://www.youtube.com/watch?v=E2Fjilze0eI'],
29
+ %q['http://www.youtube.com/watch?v=E2Fjilze0eI the bunny gets it'],
30
+ %q['A waste of chocolate http://www.youtube.com/watch?v=E2Fjilze0eI'] do |md, _|
31
+ { :title => md[1], :embed => md[2], :caption => md[3] }
32
+ end
33
+
34
+ register_format :quote, /^\s*"([^"]+)"\s+--\s*(.*?)(?:\s+\((https?:.*)\))?$/i,
35
+ %q['"adios, turd nuggets" --J.P.'],
36
+ %q['"adios, turd nuggets" --J.P. (http://imdb.com/title/tt0456554/)'] do |md, _|
37
+ { :quote => md[1], :source => md[2], :url => md[3] }
38
+ end
39
+
40
+ register_format :link, %r{^\s*(?:(.*?)\s+)?(https?://\S+)\s*(?:\s+(\S.*))?$}i,
41
+ %q['http://news.yahoo.com/s/ap/20071203/ap_on_sc/dinosaur_mummy'],
42
+ %q['http://news.yahoo.com/s/ap/20071203/ap_on_sc/dinosaur_mummy shows just how fast a mummified dinosaur can be'],
43
+ %q['Fossilized Hadrosaur http://news.yahoo.com/s/ap/20071203/ap_on_sc/dinosaur_mummy'] do |md, _|
44
+ { :name => md[1], :url => md[2], :description => md[3] }
45
+ end
46
+
47
+ register_format :fact, %r{^\s*fact:\s+(.*)}i,
48
+ %q['FACT: Zed Shaw doesn't do pushups, he pushes the earth down'] do |md, _|
49
+ { :title => "FACT: #{md[1]}" }
50
+ end
51
+
52
+ register_format :true_or_false, %r{^\s*(?:(?:true\s+or\s+false)|(?:t\s+or\s+f))\s*[:\?]\s+(.*)}i,
53
+ %q['T or F: the human body has more than one sphincter'],
54
+ %q['true or false: the human body has more than one sphincter'],
55
+ %q['true or false? the human body has more than one sphincter'] do |md, _|
56
+ { :title => "True or False? #{md[1]}" }
57
+ end
58
+
59
+ register_format :definition, %r{^\s*defin(?:e|ition):?\s+(.*?)\s*(?:[:=]|as)\s*(.*)}i,
60
+ %q['Definition: tardulism: the ideology of the tard culture'],
61
+ %q['Definition: tardulism = the ideology of the tard culture'],
62
+ %q["define tardulism as the ideology of the tard culture"] do |md, _|
63
+ { :title => "DEFINITION: #{md[1]}: #{md[2]}" }
64
+ end
65
+
66
+ def parse(sender, channel, mesg)
67
+ return nil if mesg.empty?
68
+
69
+ common = { :poster => sender, :channel => channel }
70
+
71
+ result = nil
72
+ formats.detect { |f| result = f.process(mesg) }
73
+
74
+ return nil unless result
75
+
76
+ result = common.merge(result)
77
+ result
78
+ end
79
+ end
@@ -0,0 +1,23 @@
1
+ class BotParserFormat
2
+ attr_reader :name, :format, :block
3
+
4
+ def initialize(name, format, *description, &block)
5
+ raise ArgumentError, 'Block needed' if block.nil?
6
+
7
+ @name = name
8
+ @format = format
9
+ @block = block
10
+ @description = description
11
+ end
12
+
13
+ def description
14
+ @description.empty? ? nil : @description.join("\n")
15
+ end
16
+
17
+ def process(text)
18
+ md = format.match(text)
19
+ return nil unless md
20
+
21
+ block.call(md, text).merge(:type => name)
22
+ end
23
+ end
@@ -0,0 +1,46 @@
1
+ class BotSender
2
+ attr_reader :kind
3
+
4
+ @@kinds = { }
5
+
6
+ def self.kinds
7
+ @@kinds.keys.sort_by {|k| k.to_s }
8
+ end
9
+
10
+ def self.register(args = {})
11
+ args.each_pair {|k,v| @@kinds[k] = v }
12
+ end
13
+
14
+ def self.new(args = {})
15
+ raise ArgumentError unless self.kinds.include?(args[:destination])
16
+ obj = @@kinds[args[:destination]].allocate
17
+ obj.send :initialize, args
18
+ obj
19
+ end
20
+
21
+ def initialize(args = {})
22
+ validate(args)
23
+ @kind = args[:destination]
24
+ end
25
+
26
+ def deliver(message)
27
+ return nil unless message and message[:type]
28
+ meth = "do_#{message[:type]}".to_sym
29
+ raise ArgumentError, "unknown message type [#{message[:type]}]" unless self.respond_to?(meth)
30
+ begin
31
+ self.send(meth, message)
32
+ rescue Exception => e
33
+ return e.to_s
34
+ end
35
+ end
36
+
37
+ # validate arguments when creating a specific BotSender type instance
38
+ def validate(args = {})
39
+ end
40
+ end
41
+
42
+ require 'senders/tumblr'
43
+
44
+ class BotSender
45
+ @@kinds[:tumblr] = BotSender::Tumblr
46
+ end
File without changes
@@ -0,0 +1,191 @@
1
+ module ObjectDaddy
2
+
3
+ def self.included(klass)
4
+ klass.extend ClassMethods
5
+ if defined? ActiveRecord and klass < ActiveRecord::Base
6
+ klass.extend RailsClassMethods
7
+
8
+ class << klass
9
+ alias_method :validates_presence_of_without_object_daddy, :validates_presence_of
10
+ alias_method :validates_presence_of, :validates_presence_of_with_object_daddy
11
+ end
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+ attr_accessor :exemplars_generated, :exemplar_path, :generators
17
+ attr_reader :presence_validated_attributes
18
+ protected :exemplars_generated=
19
+
20
+ # create a valid instance of this class, using any known generators
21
+ def spawn(args = {})
22
+ gather_exemplars
23
+ (generators || {}).each_pair do |handle, gen_data|
24
+ next if args[handle]
25
+ generator = gen_data[:generator]
26
+ if generator[:block]
27
+ if generator[:start]
28
+ generator[:prev] = args[handle] = generator[:start]
29
+ generator.delete(:start)
30
+ else
31
+ generator[:prev] = args[handle] = generator[:block].call(generator[:prev])
32
+ end
33
+ elsif generator[:method]
34
+ args[handle] = send(generator[:method])
35
+ elsif generator[:class]
36
+ args[handle] = generator[:class].next
37
+ end
38
+ end
39
+ if presence_validated_attributes and !presence_validated_attributes.empty?
40
+ req = {}
41
+ (presence_validated_attributes.keys - args.keys).each {|a| req[a.to_s] = true } # find attributes required by validates_presence_of not already set
42
+
43
+ belongs_to_associations = reflect_on_all_associations(:belongs_to).to_a
44
+ missing = belongs_to_associations.select { |a| req[a.name.to_s] or req[a.primary_key_name.to_s] }
45
+ if create_scope = scope(:create)
46
+ missing.reject! { |a| create_scope.include?(a.primary_key_name) }
47
+ end
48
+ missing.each {|a| args[a.name] = a.class_name.constantize.generate }
49
+ end
50
+ new(args)
51
+ end
52
+
53
+ # register a generator for an attribute of this class
54
+ # generator_for :foo do |prev| ... end
55
+ # generator_for :foo do ... end
56
+ # generator_for :foo, value
57
+ # generator_for :foo => value
58
+ # generator_for :foo, :class => GeneratorClass
59
+ # generator_for :foo, :method => :method_name
60
+ def generator_for(handle, args = {}, &block)
61
+ if handle.is_a?(Hash)
62
+ raise ArgumentError, "only specify one attr => value pair at a time" unless handle.keys.length == 1
63
+ gen_data = handle
64
+ handle = gen_data.keys.first
65
+ args = gen_data[handle]
66
+ end
67
+
68
+ raise ArgumentError, "an attribute name must be specified" unless handle = handle.to_sym
69
+
70
+ unless args.is_a?(Hash)
71
+ unless block
72
+ retval = args
73
+ block = lambda { retval } # lambda { args } results in returning the empty hash that args gets changed to
74
+ end
75
+ args = {} # args is assumed to be a hash for the rest of the method
76
+ end
77
+
78
+ if args[:method]
79
+ record_generator_for(handle, :method => args[:method].to_sym)
80
+ elsif args[:class]
81
+ raise ArgumentError, "generator class [#{args[:class].name}] does not have a :next method" unless args[:class].respond_to?(:next)
82
+ record_generator_for(handle, :class => args[:class])
83
+ elsif block
84
+ raise ArgumentError, "generator block must take an optional single argument" unless (-1..1).include?(block.arity) # NOTE: lambda {} has an arity of -1, while lambda {||} has an arity of 0
85
+ h = { :block => block }
86
+ h[:start] = args[:start] if args[:start]
87
+ record_generator_for(handle, h)
88
+ else
89
+ raise ArgumentError, "a block, :class generator, :method generator, or value must be specified to generator_for"
90
+ end
91
+ end
92
+
93
+ def gather_exemplars
94
+ return if exemplars_generated
95
+ if superclass.respond_to?(:gather_exemplars)
96
+ superclass.gather_exemplars
97
+ self.generators = (superclass.generators || {}).dup
98
+ end
99
+
100
+ path = File.join(exemplar_path, "#{underscore(name)}_exemplar.rb")
101
+ load(path) if File.exists?(path)
102
+ self.exemplars_generated = true
103
+ end
104
+
105
+ def presence_validated_attributes
106
+ @presence_validated_attributes ||= {}
107
+ attrs = @presence_validated_attributes
108
+ if superclass.respond_to?(:presence_validated_attributes)
109
+ attrs = superclass.presence_validated_attributes.merge(attrs)
110
+ end
111
+ attrs
112
+ end
113
+
114
+ protected
115
+
116
+ # we define an underscore helper ourselves since the ActiveSupport isn't available if we're not using Rails
117
+ def underscore(string)
118
+ string.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
119
+ end
120
+
121
+ def record_generator_for(handle, generator)
122
+ self.generators ||= {}
123
+ raise ArgumentError, "a generator for attribute [:#{handle}] has already been specified" if (generators[handle] || {})[:source] == self
124
+ generators[handle] = { :generator => generator, :source => self }
125
+ end
126
+ end
127
+
128
+ module RailsClassMethods
129
+ def exemplar_path
130
+ File.join(RAILS_ROOT, 'test', 'exemplars')
131
+ end
132
+
133
+ def validates_presence_of_with_object_daddy(*attr_names)
134
+ @presence_validated_attributes ||= {}
135
+ new_attr = attr_names.dup
136
+ new_attr.pop if new_attr.last.is_a?(Hash)
137
+ new_attr.each {|a| @presence_validated_attributes[a] = true }
138
+ validates_presence_of_without_object_daddy(*attr_names)
139
+ end
140
+
141
+ def generate(args = {})
142
+ obj = spawn(args)
143
+ obj.save
144
+ obj
145
+ end
146
+
147
+ def generate!(args = {})
148
+ obj = spawn(args)
149
+ obj.save!
150
+ obj
151
+ end
152
+ end
153
+ end
154
+
155
+
156
+ # these additional routines are just to give us coverage for flog opcodes that we hadn't yet covered in an integration test
157
+ alias puts print
158
+ attr_writer :foo
159
+
160
+ foo = 2
161
+
162
+ case 'foo'
163
+ when :foo
164
+ true
165
+ else
166
+ false
167
+ end
168
+
169
+ class Foo
170
+ def initialize
171
+ super(:foo)
172
+ end
173
+ end
174
+
175
+ until true
176
+ true
177
+ end
178
+
179
+ while false
180
+ true
181
+ end
182
+
183
+ begin
184
+ true
185
+ rescue Exception
186
+ false
187
+ else
188
+ true
189
+ end
190
+
191
+ puts(/foo/)