ralber 0.0.1

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.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/bin/ralber.rb +46 -0
  3. data/lib/ralber/album.rb +215 -0
  4. data/lib/ralber/commands/create_command.rb +39 -0
  5. data/lib/ralber/commands/publish_command.rb +72 -0
  6. data/lib/ralber/commands/update_command.rb +31 -0
  7. data/lib/ralber/image.rb +155 -0
  8. data/lib/ralber/observable.rb +17 -0
  9. data/lib/ralber/publisher.rb +167 -0
  10. data/lib/ralber/template.rb +56 -0
  11. data/templates/default/css/pure/pure-min.css +11 -0
  12. data/templates/default/css/styles.css +165 -0
  13. data/templates/default/detail.html.erb +41 -0
  14. data/templates/default/fonts/FiraSans-Light.eot +0 -0
  15. data/templates/default/fonts/FiraSans-Light.otf +0 -0
  16. data/templates/default/fonts/FiraSans-Light.ttf +0 -0
  17. data/templates/default/fonts/FiraSans-Light.woff +0 -0
  18. data/templates/default/fonts/FiraSans-LightItalic.eot +0 -0
  19. data/templates/default/fonts/FiraSans-LightItalic.otf +0 -0
  20. data/templates/default/fonts/FiraSans-LightItalic.ttf +0 -0
  21. data/templates/default/fonts/FiraSans-LightItalic.woff +0 -0
  22. data/templates/default/fonts/font-awesome-4.2.0/css/font-awesome.min.css +4 -0
  23. data/templates/default/fonts/font-awesome-4.2.0/fonts/FontAwesome.otf +0 -0
  24. data/templates/default/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.eot +0 -0
  25. data/templates/default/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.svg +520 -0
  26. data/templates/default/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.ttf +0 -0
  27. data/templates/default/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.woff +0 -0
  28. data/templates/default/index.html.erb +61 -0
  29. data/templates/default/template.json +25 -0
  30. data/templates/fancybox-dark/css/pure/pure-min.css +11 -0
  31. data/templates/fancybox-dark/css/styles.css +165 -0
  32. data/templates/fancybox-dark/detail.html.erb +41 -0
  33. data/templates/fancybox-dark/fancybox/CHANGELOG.md +125 -0
  34. data/templates/fancybox-dark/fancybox/README.md +217 -0
  35. data/templates/fancybox-dark/fancybox/lib/jquery-1.10.1.min.js +6 -0
  36. data/templates/fancybox-dark/fancybox/lib/jquery-1.9.0.min.js +4 -0
  37. data/templates/fancybox-dark/fancybox/lib/jquery.mousewheel-3.0.6.pack.js +13 -0
  38. data/templates/fancybox-dark/fancybox/source/blank.gif +0 -0
  39. data/templates/fancybox-dark/fancybox/source/fancybox_loading.gif +0 -0
  40. data/templates/fancybox-dark/fancybox/source/fancybox_loading@2x.gif +0 -0
  41. data/templates/fancybox-dark/fancybox/source/fancybox_overlay.png +0 -0
  42. data/templates/fancybox-dark/fancybox/source/fancybox_sprite.png +0 -0
  43. data/templates/fancybox-dark/fancybox/source/fancybox_sprite@2x.png +0 -0
  44. data/templates/fancybox-dark/fancybox/source/helpers/fancybox_buttons.png +0 -0
  45. data/templates/fancybox-dark/fancybox/source/helpers/jquery.fancybox-buttons.css +97 -0
  46. data/templates/fancybox-dark/fancybox/source/helpers/jquery.fancybox-buttons.js +122 -0
  47. data/templates/fancybox-dark/fancybox/source/helpers/jquery.fancybox-media.js +199 -0
  48. data/templates/fancybox-dark/fancybox/source/helpers/jquery.fancybox-thumbs.css +55 -0
  49. data/templates/fancybox-dark/fancybox/source/helpers/jquery.fancybox-thumbs.js +162 -0
  50. data/templates/fancybox-dark/fancybox/source/jquery.fancybox.css +274 -0
  51. data/templates/fancybox-dark/fancybox/source/jquery.fancybox.js +2020 -0
  52. data/templates/fancybox-dark/fancybox/source/jquery.fancybox.pack.js +46 -0
  53. data/templates/fancybox-dark/fonts/FiraSans-Light.eot +0 -0
  54. data/templates/fancybox-dark/fonts/FiraSans-Light.otf +0 -0
  55. data/templates/fancybox-dark/fonts/FiraSans-Light.ttf +0 -0
  56. data/templates/fancybox-dark/fonts/FiraSans-Light.woff +0 -0
  57. data/templates/fancybox-dark/fonts/FiraSans-LightItalic.eot +0 -0
  58. data/templates/fancybox-dark/fonts/FiraSans-LightItalic.otf +0 -0
  59. data/templates/fancybox-dark/fonts/FiraSans-LightItalic.ttf +0 -0
  60. data/templates/fancybox-dark/fonts/FiraSans-LightItalic.woff +0 -0
  61. data/templates/fancybox-dark/fonts/font-awesome-4.2.0/css/font-awesome.min.css +4 -0
  62. data/templates/fancybox-dark/fonts/font-awesome-4.2.0/fonts/FontAwesome.otf +0 -0
  63. data/templates/fancybox-dark/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.eot +0 -0
  64. data/templates/fancybox-dark/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.svg +520 -0
  65. data/templates/fancybox-dark/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.ttf +0 -0
  66. data/templates/fancybox-dark/fonts/font-awesome-4.2.0/fonts/fontawesome-webfont.woff +0 -0
  67. data/templates/fancybox-dark/index.html.erb +79 -0
  68. data/templates/fancybox-dark/template.json +20 -0
  69. metadata +167 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6b60444e1324682dac3a7d030dff87746500e2c2
4
+ data.tar.gz: bcbc2b32ad77e4b91af37be4661e81b8350fb8cb
5
+ SHA512:
6
+ metadata.gz: 1487111943be6a4f493c756c6dcbd1df162a90d4cd5b287beac10d013ad2f971aad2e674f7f29d217466fe2ce2de390930f87f71563a79adfbcc4e6a1a537386
7
+ data.tar.gz: 6676c3917f20fd98dc1415f42f71b2bb73398e777f09f3ee0b6bd9e871818fe06affe59893f6a06e264f2383adfcf382df0433ace81b75a789e55719362bcd39
data/bin/ralber.rb ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # -*- encoding: utf-8 -*-
4
+ $:.push File.expand_path("..", __FILE__)
5
+
6
+ require 'rubygems'
7
+ require 'bundler/setup'
8
+ require 'commander/import'
9
+ require 'ralber/commands/create_command'
10
+ require 'ralber/commands/publish_command'
11
+ require 'ralber/commands/update_command'
12
+
13
+ program :version, '0.0.1'
14
+ program :description, 'A static web album generator'
15
+
16
+ command :create do |c|
17
+ c.syntax = 'ralber create [options]'
18
+ c.summary = 'Initializes the current folder as an Album.'
19
+ c.description = 'creates an initial album.json and grabs image information for all images found in the directory.'
20
+ c.example 'Simple create', 'ralber create'
21
+ c.option '--title STRING', String, 'Sets the album title. Defaults to the current folder name'
22
+ c.option '--subtitle STRING', String, 'Sets the album subtitle.'
23
+ c.option '--description STRING', String, 'Sets the album description.'
24
+ c.when_called Ralber::Commands::Create
25
+ end
26
+
27
+ command :publish do |c|
28
+ c.syntax = 'ralber publish [options]'
29
+ c.summary = 'Publishes an existing album: Copies the images and web content, and generates the dynamic files.'
30
+ c.description = ''
31
+ c.option '--template STRING', String, 'Name or path to a Template'
32
+ c.option '--to STRING',String, 'Destination path to which the web album is published'
33
+ c.option '--save',String, 'If set, the album.json is updated with the delivered command line options, like publish path'
34
+ c.option '--force', 'If set, all images are (re-)created, even if they already exist in the destination. Default is to not override any images.'
35
+ c.example 'Simple publish', 'ralber publish --to /path/to/final/destination'
36
+ c.when_called Ralber::Commands::Publish
37
+ end
38
+
39
+ command :update do |c|
40
+ c.syntax = 'ralber update [options]'
41
+ c.summary = 'Updates the actual album.'
42
+ c.description = 'Updates the album.json file with new / removed images, and updates image information.'
43
+ c.example 'Simple update', 'ralber update'
44
+ c.when_called Ralber::Commands::Update
45
+ end
46
+
@@ -0,0 +1,215 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'json'
5
+ require 'ralber/image'
6
+ require 'ralber/observable'
7
+
8
+ module Ralber
9
+ class Album
10
+ include Observable
11
+
12
+ attr :path
13
+ attr_reader :title, :subtitle, :description, :destination, :images, :template, :album_info
14
+ attr_writer :title, :subtitle, :description, :destination, :template
15
+
16
+ def initialize(path)
17
+ raise IOError, "directory does not exist: #{path}" if not Dir.exists?(path)
18
+ @path = File.expand_path(path)
19
+ @album_info = self.get_album_info
20
+ @images = self.collect_images(@album_info['images'])
21
+ end
22
+
23
+ def title
24
+ return @album_info['title']
25
+ end
26
+
27
+ def title=(value)
28
+ @album_info['title'] = value
29
+ self
30
+ end
31
+
32
+ def subtitle
33
+ return @album_info['subtitle']
34
+ end
35
+ def subtitle=(value)
36
+ @album_info['subtitle'] = value
37
+ self
38
+ end
39
+
40
+ def destination
41
+ return @album_info['destination']
42
+ end
43
+ def destination=(value)
44
+ @album_info['destination'] = value
45
+ self
46
+ end
47
+
48
+ def description
49
+ return @album_info['description']
50
+ end
51
+ def description=(value)
52
+ @album_info['description'] = value
53
+ self
54
+ end
55
+
56
+ def template
57
+ return @album_info['template']
58
+ end
59
+ def template=(value)
60
+ @album_info['template'] = value
61
+ self
62
+ end
63
+
64
+ def author
65
+ return @album_info['author']
66
+ end
67
+
68
+ def author=(value)
69
+ @album_info['author'] = value
70
+ self
71
+ end
72
+
73
+ def copyright
74
+ return @album_info['copyright']
75
+ end
76
+
77
+ def copyright=(value)
78
+ @album_info['copyright'] = value
79
+ self
80
+ end
81
+
82
+
83
+ ##
84
+ # creates an album.json file, and invokes the json creation for each
85
+ # image found in the album
86
+ def create(options = {})
87
+ @images = []
88
+ info = self.get_new_info
89
+ Dir.entries(@path).find_all { |f| File.file?(File.join(@path,f)) }.map{|f| File.join(@path,f)}.each do |f|
90
+ begin
91
+ img = Image.new(f)
92
+ img.create
93
+ @images << img
94
+ yield img if block_given?
95
+ info['images'] << File.basename(f)
96
+ rescue
97
+ end
98
+ end
99
+
100
+ @album_info = info
101
+ (@album_info['title'] = options['title']) if options.key?('title')
102
+ (@album_info['subtitle'] = options['subtitle']) if options.key?('subtitle')
103
+ (@album_info['description'] = options['description']) if options.key?('description')
104
+ (@album_info['author'] = options['author']) if options.key?('author')
105
+ (@album_info['copyright'] = options['copyright']) if options.key?('copyright')
106
+ self.write_albuminfo
107
+ end
108
+
109
+ def write_albuminfo
110
+ FileUtils.mkdir_p(File.dirname self.json_path)
111
+ images = @images.map {|img| File.basename(img.path)}
112
+ @album_info['images'] = images
113
+ open(self.json_path,'w') do |f|
114
+ f.write(JSON.pretty_generate(@album_info))
115
+ end
116
+ end
117
+
118
+ def json_path
119
+ File.expand_path(File.join(@path,'.ralber','album.json'))
120
+ end
121
+
122
+ def get_new_info
123
+ {
124
+ "title" => File.basename(@path),
125
+ "subtitle" => '',
126
+ "description" => '',
127
+ "author" => '',
128
+ "copyright" => '',
129
+ "images" => [],
130
+ "template" => nil,
131
+ "destination" => nil
132
+ }
133
+ end
134
+
135
+ ##
136
+ # Reads the album metainfo from the album.json file, if present,
137
+ # or sets apropriate defaults.
138
+ def get_album_info
139
+ info = self.get_new_info
140
+ if File.exists?(json_path)
141
+ begin
142
+ data = JSON.parse(File.read(json_path))
143
+ if data.respond_to?(:key?)
144
+ (info['title'] = data['title']) if data.key?('title')
145
+ (info['subtitle'] = data['subtitle']) if data.key?('subtitle')
146
+ (info['description'] = data['description']) if data.key?('description')
147
+ (info['author'] = data['author']) if data.key?('author')
148
+ (info['copyright'] = data['copyright']) if data.key?('copyright')
149
+ (info['images'] = data['images']) if data.key?('images')
150
+ (info['template'] = data['template']) if data.key?('template')
151
+ (info['index'] = data['index']) if data.key?('index')
152
+ (info['detail'] = data['detail']) if data.key?('detail')
153
+ (info['destination'] = data['destination']) if data.key?('destination')
154
+ end
155
+ rescue
156
+ end
157
+ end
158
+ return info
159
+ end
160
+
161
+ ##
162
+ # fetches all the imags in the album dir, creating Image instances from them
163
+ # and return an array of Image objects.
164
+ def collect_images(image_names, folder = nil)
165
+ folder = @path if not folder
166
+ images = []
167
+ image_names.each do | imgname |
168
+ imgpath = File.join(folder,imgname)
169
+ begin
170
+ img = Image.new(imgpath)
171
+ if img.type
172
+ images << img
173
+ yield img if block_given?
174
+ end
175
+ rescue
176
+ end
177
+ end
178
+ return images
179
+ end
180
+
181
+ def image_index(image)
182
+ return @images.index(image)
183
+ end
184
+
185
+ def update
186
+ img_files = Dir.entries(@path).find_all { |f| File.file?(File.join(@path,f)) }.map{|f| File.join(@path,f)}
187
+
188
+ # The following situation could happen:
189
+ # 1. when the Image object is present, the image config and the file is OK, no action needed.
190
+ # 2. remaining image files need to be added
191
+ # 3. orphaned config files need to be removed
192
+ new_images = []
193
+ @images.each_with_index do | img, index |
194
+ # all images in the @images array are still OK and present, we just re-append them:
195
+ new_images << img
196
+
197
+ # remove entry from the found image files, as those are OK:
198
+ img_files.delete_if {|img_file| File.basename(img_file) == File.basename(img.path)}
199
+ end
200
+ @images = new_images
201
+
202
+ # remaining image files without album entry: we need to process them as new images:
203
+ img_files.each do | new_file |
204
+ begin
205
+ img = Image.new(new_file)
206
+ self.inform_listeners(:update, "new image found: #{new_file}")
207
+ img.create
208
+ @images << img
209
+ rescue
210
+ end
211
+ end
212
+ self.write_albuminfo
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,39 @@
1
+ require 'highline/import'
2
+ require 'ralber/album'
3
+
4
+ module Ralber
5
+ module Commands
6
+ class Create
7
+ def initialize(args, options)
8
+ self.set_defaults(options)
9
+ @options = options
10
+ self.ask_title if options.title == nil
11
+ self.create_album
12
+ end
13
+
14
+ def set_defaults(options)
15
+ options.default \
16
+ :title => nil
17
+ end
18
+
19
+ def ask_title
20
+ @options.title = ask("Album title? ", String)
21
+ end
22
+
23
+ def create_album
24
+ puts("Creating album '#{@options.title}' in #{Dir.pwd}")
25
+ album = Ralber::Album.new(Dir.pwd)
26
+ album.create({
27
+ 'title' => @options.title,
28
+ 'subtitle' => @options.subtitle,
29
+ 'description' => @options.description
30
+ }) do |img|
31
+ print "."
32
+ end
33
+
34
+ puts("\nDone. Found #{album.images.length} images. You can now edit album.json and/or publish the album.")
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,72 @@
1
+ require 'highline/import'
2
+ require 'pathname'
3
+ require 'ralber/album'
4
+ require 'ralber/template'
5
+ require 'ralber/publisher'
6
+
7
+ module Ralber
8
+ module Commands
9
+ class Publish
10
+ def initialize(args, options)
11
+ @album = Ralber::Album.new(Dir.pwd)
12
+ self.set_defaults(options)
13
+ @options = options
14
+ self.publish
15
+ end
16
+
17
+ def set_defaults(options)
18
+ options.default \
19
+ :title => nil
20
+ end
21
+
22
+ def configure_template
23
+ tpl = @options.template
24
+ tpl = @album.template unless tpl
25
+ tpl = "default" unless tpl
26
+ tplObj = nil
27
+ begin
28
+ tplObj = Ralber::Template.new(tpl, File.join(File.dirname(Gem.bin_path('ralber','ralber.rb')),'..','templates'))
29
+ @album.template = tpl
30
+ rescue
31
+ puts "Could not find template. Either give the name or path to a template via --template parameter, or put a 'template' config in album.json."
32
+ exit 2
33
+ end
34
+ return tplObj
35
+ end
36
+
37
+ def configure_destination
38
+ dest = @options.to
39
+ dest = @album.destination unless dest
40
+
41
+ if not dest
42
+ puts "Please provide a destination path with --to <path>"
43
+ exit 2
44
+ end
45
+
46
+ @album.destination = dest
47
+
48
+ if not (Pathname.new dest).absolute?
49
+ dest = File.join(@album.path,dest)
50
+ end
51
+
52
+ return dest
53
+ end
54
+
55
+ def publish
56
+ template = self.configure_template
57
+ dest = self.configure_destination
58
+
59
+ puts "please wait, work in progress..."
60
+ publisher = Ralber::Publisher.new(@album, template)
61
+ publisher.force = @options.force
62
+ publisher.add_listener(self)
63
+ publisher.publish_to(dest)
64
+ publisher.save_album if @options.save
65
+ end
66
+
67
+ def message(context, message)
68
+ puts message
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,31 @@
1
+ require 'highline/import'
2
+ require 'pathname'
3
+ require 'ralber/album'
4
+
5
+ module Ralber
6
+ module Commands
7
+ class Update
8
+ def initialize(args, options)
9
+ @album = Ralber::Album.new(Dir.pwd)
10
+ self.set_defaults(options)
11
+ @options = options
12
+ self.update
13
+ end
14
+
15
+ def set_defaults(options)
16
+ options.default \
17
+ :title => nil
18
+ end
19
+
20
+ def update
21
+ puts "please wait, work in progress..."
22
+ @album.add_listener(self)
23
+ @album.update
24
+ end
25
+
26
+ def message(context, message)
27
+ puts message
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,155 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'json'
5
+ require 'rmagick'
6
+
7
+ module Ralber
8
+
9
+ ##
10
+ # Represents an image with its metadata. Performs also converting
11
+ # functions like thumbs etc.
12
+ class Image
13
+ attr :path
14
+ attr_reader :title, :type, :description, :width, :height
15
+
16
+ def initialize(path)
17
+ raise StandardError, "File does not exits" if not File.exists?(path)
18
+ @path = File.expand_path(path)
19
+ @image_info = self.get_image_info
20
+ end
21
+
22
+ def title
23
+ @image_info['title']
24
+ end
25
+ def type
26
+ @image_info['type']
27
+ end
28
+ def description
29
+ @image_info['description']
30
+ end
31
+ def width
32
+ @image_info['width']
33
+ end
34
+ def height
35
+ @image_info['height']
36
+ end
37
+
38
+ ##
39
+ # creates the initial image.json file, extracting the metadata
40
+ # if possible. If the image is not recognized, an exception is raised.
41
+ def create
42
+ @image_info = get_new_info
43
+ meta = self.image_metadata
44
+ type = meta[:type]
45
+ raise StandardError, "Unknown image type" if not type
46
+ @image_info['type'] = type
47
+ @image_info['width'] = meta[:width]
48
+ @image_info['height'] = meta[:height]
49
+
50
+ self.write_imageinfo
51
+ end
52
+
53
+ def write_imageinfo
54
+ FileUtils.mkdir_p(File.dirname json_path)
55
+ open(self.json_path,'w') do |f|
56
+ f.write(JSON.pretty_generate(@image_info))
57
+ end
58
+ end
59
+
60
+ def json_path
61
+ dir = File.join(File.dirname(@path),'.ralber')
62
+ base = File.basename(@path)
63
+ File.expand_path(File.join(dir,base+'.json'))
64
+ end
65
+
66
+ def get_new_info
67
+ {
68
+ "title" => File.basename(@path),
69
+ "type" => nil,
70
+ "description" => '',
71
+ "width" => 0,
72
+ "height" => 0
73
+ }
74
+ end
75
+
76
+ ##
77
+ # reads image metainfos from the image file and, if present,
78
+ # from the image.json file.
79
+ def get_image_info
80
+ info = get_new_info
81
+ if File.exists?(json_path)
82
+ begin
83
+ data = JSON.parse(File.read(json_path))
84
+ if data.respond_to?(:key?)
85
+ (info['title'] = data['title']) if data.key?('title')
86
+ (info['description'] = data['description']) if data.key?('description')
87
+ (info['type'] = data['type'].to_sym) if data.key?('type')
88
+ (info['width'] = data['width']) if data.key?('width')
89
+ (info['height'] = data['height']) if data.key?('height')
90
+ end
91
+ rescue
92
+ end
93
+ else
94
+ self.create
95
+ end
96
+ return info
97
+ end
98
+
99
+ def image_type
100
+ type = FastImage.type(@path)
101
+ raise StandardError, "Unknown image type" if not type
102
+ return type
103
+ end
104
+
105
+ def image_dimensions
106
+ dim = FastImage.size(@path)
107
+ { :width => dim[0],:height => dim[1] }
108
+ end
109
+
110
+ def image_metadata
111
+ img = Magick::Image::read(@path).first
112
+ {
113
+ :width => img.columns,
114
+ :height => img.rows,
115
+ :type => self.map_type(img.format)
116
+ }
117
+ end
118
+
119
+ def map_type(imagickType)
120
+ case imagickType
121
+ when 'JPEG' then :jpeg
122
+ when 'PNG' then :png
123
+ when 'GIF' then :gif
124
+ else nil
125
+ end
126
+ end
127
+
128
+ def create_resized_image(output_filename, geometry_string = nil)
129
+ img = Magick::Image::read(@path).first
130
+ if geometry_string
131
+ img.change_geometry!(geometry_string) { |cols, rows, manipImg|
132
+ img.resize!(cols, rows)
133
+ }
134
+ end
135
+ img.write(output_filename)
136
+ end
137
+
138
+ def create_resized_version(type, geometry_string, output_dir)
139
+ name = self.get_resized_name(@path, type)
140
+ outfile = File.join(output_dir,name)
141
+ self.create_resized_image(outfile,geometry_string)
142
+ end
143
+
144
+ def get_resized_name(path, type)
145
+ name = File.basename(path,'.*')
146
+ case type
147
+ when :jpeg then name += '.jpg'
148
+ when :jpg then name += '.jpg'
149
+ when :png then name += '.png'
150
+ else name = File.basename(path)
151
+ end
152
+ return name
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,17 @@
1
+ module Ralber
2
+ module Observable
3
+ def add_listener(listener)
4
+ @listeners = [] unless @listeners
5
+ @listeners << listener
6
+ end
7
+
8
+ def inform_listeners(msg_context,message)
9
+ if not @listeners.respond_to?(:each)
10
+ return;
11
+ end
12
+ @listeners.each { |listener|
13
+ listener.message(msg_context,message) if listener.respond_to?(:message)
14
+ }
15
+ end
16
+ end
17
+ end