osm 0.0.17 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,59 +1,74 @@
1
1
  module Osm
2
2
 
3
3
  class Section
4
+ class FlexiRecord; end # Ensure the constant exists for the validators
4
5
 
5
- attr_reader :id, :name, :subscription_level, :subscription_expires, :type, :num_scouts, :column_names, :fields, :intouch_fields, :mobile_fields, :flexi_records, :role
6
- # @!attribute [r] id
6
+ include ::ActiveAttr::MassAssignmentSecurity
7
+ include ::ActiveAttr::Model
8
+
9
+ # @!attribute [rw] id
7
10
  # @return [Fixnum] the id for the section
8
- # @!attribute [r] name
11
+ # @!attribute [rw] name
9
12
  # @return [String] the section name
10
- # @!attribute [r] subscription_level
13
+ # @!attribute [rw] subscription_level
11
14
  # @return [Symbol] what subscription the section has to OSM (:bronze, :silver or :gold)
12
- # @!attribute [r] subscription_expires
15
+ # @!attribute [rw] subscription_expires
13
16
  # @return [Date] when the section's subscription to OSM expires
14
- # @!attribute [r] type
17
+ # @!attribute [rw] type
15
18
  # @return [Symbol] the section type (:beavers, :cubs, :scouts, :exporers, :adults, :waiting, :unknown)
16
- # @!attribute [r] num_scouts
19
+ # @!attribute [rw] num_scouts
17
20
  # @return [Fixnum] how many members the section has
18
- # @!attribute [r] column_names
21
+ # @!attribute [rw] column_names
19
22
  # @return [Hash] custom names to use for the data columns
20
- # @!attribute [r] fields
23
+ # @!attribute [rw] fields
21
24
  # @return [Hash] which columns are shown in OSM
22
- # @!attribute [r] intouch_fields
25
+ # @!attribute [rw] intouch_fields
23
26
  # @return [Hash] which columns are shown in OSM's in touch reports
24
- # @!attribute [r] mobile_fields
27
+ # @!attribute [rw] mobile_fields
25
28
  # @return [Hash] which columns are shown in the OSM mobile app
26
- # @!attribute [r] flexi_records
29
+ # @!attribute [rw] flexi_records
27
30
  # @return [Array<FlexiRecord>] list of the extra records the section has
28
- # @!attribute [r] role
31
+ # @!attribute [rw] role
29
32
  # @return [Osm::Role] the role linking the user to this section
30
33
 
31
-
32
- # Initialize a new Section
33
- # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
34
- def initialize(attributes={})
35
- raise ArgumentError, ':id must be nil or a Fixnum > 0' unless attributes[:id].nil? || (attributes[:id].is_a?(Fixnum) && attributes[:id] > 0)
36
- raise ArgumentError, ':section_name must be nil or a String' unless attributes[:section_name].nil? || attributes[:section_name].is_a?(String)
37
- raise ArgumentError, ':num_scouts must be nil or a Fixnum >= 0' unless attributes[:num_scouts].nil? || (attributes[:num_scouts].is_a?(Fixnum) && attributes[:num_scouts] >= 0)
38
- [:column_names, :fields, :intouch_fields, :mobile_fields].each do |attribute|
39
- raise ArgumentError, ":#{attribute} must be nil or a Hash" unless attributes[attribute].nil? || attributes[attribute].is_a?(Hash)
40
- end
41
- [:type, :subscription_level].each do |attribute|
42
- raise ArgumentError, ":#{attribute} must be nil or a Symbol" unless attributes[attribute].nil? || attributes[attribute].is_a?(Symbol)
43
- end
44
- raise ArgumentError, ':flexi_records must be nil or an Array' unless attributes[:flexi_records].nil? || attributes[:flexi_records].is_a?(Array)
45
-
46
- attributes.each { |k,v| instance_variable_set("@#{k}", v) }
47
-
48
- @section_name ||= ''
49
- @column_names ||= {}
50
- @fields ||= {}
51
- @intouch_fields ||= {}
52
- @mobile_fields ||= {}
53
- @flexi_records ||= []
54
- @subscription_level ||= :unknown
55
- @type ||= :unknown
56
- end
34
+ attribute :id, :type => Integer
35
+ attribute :name, :type => String
36
+ attribute :subscription_level, :default => :unknown
37
+ attribute :subscription_expires, :type => Date
38
+ attribute :type, :default => :unknown
39
+ attribute :num_scouts, :type => Integer
40
+ attribute :column_names, :default => {}
41
+ attribute :fields, :default => {}
42
+ attribute :intouch_fields, :default => {}
43
+ attribute :mobile_fields, :default => {}
44
+ attribute :flexi_records, :default => []
45
+ attribute :role
46
+
47
+ attr_accessible :id, :name, :subscription_level, :subscription_expires, :type, :num_scouts, :column_names, :fields, :intouch_fields, :mobile_fields, :flexi_records, :role
48
+
49
+ validates_numericality_of :id, :only_integer=>true, :greater_than=>0, :allow_nil => true
50
+ validates_numericality_of :num_scouts, :only_integer=>true, :greater_than_or_equal_to=>0
51
+ validates_presence_of :subscription_level
52
+ validates_presence_of :subscription_expires
53
+ validates_presence_of :type
54
+ validates_presence_of :column_names, :unless => Proc.new { |a| a.column_names == {} }
55
+ validates_presence_of :fields, :unless => Proc.new { |a| a.fields == {} }
56
+ validates_presence_of :intouch_fields, :unless => Proc.new { |a| a.intouch_fields == {} }
57
+ validates_presence_of :mobile_fields, :unless => Proc.new { |a| a.mobile_fields == {} }
58
+ validates_presence_of :flexi_records, :unless => Proc.new { |a| a.flexi_records == [] }
59
+ validates_presence_of :role
60
+
61
+ validates_inclusion_of :subscription_level, :in => [:bronze, :silver, :gold, :unknown], :message => 'is not a valid level'
62
+
63
+ validates :column_names, :hash => {:key_type => Symbol, :value_type => String}
64
+ validates :fields, :hash => {:key_type => Symbol, :value_type => String}
65
+ validates :intouch_fields, :hash => {:key_type => Symbol, :value_type => String}
66
+ validates :mobile_fields, :hash => {:key_type => Symbol, :value_type => String}
67
+
68
+
69
+ # @!method initialize
70
+ # Initialize a new Section
71
+ # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
57
72
 
58
73
 
59
74
  # Initialize a new Sections from api data
@@ -80,12 +95,10 @@ module Osm
80
95
  :flexi_records => [],
81
96
  }
82
97
 
83
-
84
98
  # Populate arrays
85
99
  (data['extraRecords'].is_a?(Array) ? data['extraRecords'] : []).each do |record_data|
86
100
  attributes[:flexi_records].push FlexiRecord.from_api(record_data)
87
101
  end
88
- attributes[:flexi_records].freeze
89
102
 
90
103
  new(attributes)
91
104
  end
@@ -93,7 +106,7 @@ module Osm
93
106
  # Check if this section is one of the youth sections
94
107
  # @return [Boolean]
95
108
  def youth_section?
96
- [:beavers, :cubs, :scouts, :explorers].include?(@type)
109
+ [:beavers, :cubs, :scouts, :explorers].include?(type)
97
110
  end
98
111
 
99
112
  # Custom section type checkers
@@ -117,7 +130,7 @@ module Osm
117
130
  # @return (Boolean)
118
131
  [:beavers, :cubs, :scouts, :explorers, :adults, :waiting].each do |attribute|
119
132
  define_method "#{attribute}?" do
120
- @type == attribute
133
+ type == attribute
121
134
  end
122
135
  end
123
136
 
@@ -136,29 +149,49 @@ module Osm
136
149
  return false
137
150
  end
138
151
  end
152
+
153
+ def inspect
154
+ attribute_descriptions = attributes.merge('role' => role.inspect_without_section(self))
155
+ return_inspect(attribute_descriptions)
156
+ end
139
157
 
158
+ def inspect_without_role(exclude_role)
159
+ attribute_descriptions = (role == exclude_role) ? attributes.merge('role' => 'SET') : attributes
160
+ return_inspect(attribute_descriptions)
161
+ end
140
162
 
141
163
 
142
164
  private
165
+ def return_inspect(attribute_descriptions)
166
+ attribute_descriptions.sort.map { |key, value| "#{key}: #{key.eql?('role') ? value : value.inspect}" }.join(", ")
167
+ separator = " " unless attribute_descriptions.empty?
168
+ "#<#{self.class.name}#{separator}#{attribute_descriptions}>"
169
+ end
170
+
143
171
  class FlexiRecord
172
+ include ::ActiveAttr::MassAssignmentSecurity
173
+ include ::ActiveAttr::Model
144
174
 
145
- attr_reader :id, :name
146
- # @!attribute [r] id
175
+ # @!attribute [rw] id
147
176
  # @return [Fixnum] the aid of the flexi-record
148
- # @!attribute [r] name
177
+ # @!attribute [rw] name
149
178
  # @return [String] the name given to the flexi-record
150
-
151
- # Initialize a new ApiAccess
152
- # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
153
- def initialize(attributes={})
154
- raise ArgumentError, ':id must be a Fixnum > 0' unless (attributes[:id].is_a?(Fixnum) && attributes[:id] > 0)
155
- raise ArgumentError, ':name must be a String' unless attributes[:name].is_a?(String)
156
-
157
- attributes.each { |k,v| instance_variable_set("@#{k}", v) }
158
- end
159
-
160
-
161
- # Initialize a new ApiAccess from api data
179
+
180
+ attribute :id, :type => Integer
181
+ attribute :name, :type => String
182
+
183
+ attr_accessible :id, :name
184
+
185
+ validates_numericality_of :id, :only_integer=>true, :greater_than=>0
186
+ validates_presence_of :name
187
+
188
+
189
+ # @!method initialize
190
+ # Initialize a new FlexiRecord
191
+ # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
192
+
193
+
194
+ # Initialize a new FlexiRecord from api data
162
195
  # @param [Hash] data the hash of data provided by the API
163
196
  def self.from_api(data)
164
197
  # Expect item to be: {:name=>String, :extraid=>Fixnum}
@@ -170,8 +203,8 @@ module Osm
170
203
  :name => data['name'],
171
204
  })
172
205
  end
173
- end # FlexiRecord
206
+ end # Class Section::FlexiRecord
174
207
 
175
- end # Section
208
+ end # Class Section
176
209
 
177
210
  end # Module
@@ -1,30 +1,38 @@
1
1
  module Osm
2
2
 
3
3
  class Term
4
+ include ::ActiveAttr::MassAssignmentSecurity
5
+ include ::ActiveAttr::Model
4
6
 
5
- attr_reader :id, :section_id, :name, :start, :end
6
- # @!attribute [r] id
7
+ # @!attribute [rw] id
7
8
  # @return [Fixnum] the id for the term
8
- # @!attribute [r] section_id
9
+ # @!attribute [rw] section_id
9
10
  # @return [Fixnum] the section the term belongs to
10
- # @!attribute [r] name
11
+ # @!attribute [rw] name
11
12
  # @return [Fixnum] the name of the term
12
- # @!attribute [r] start
13
+ # @!attribute [rw] start
13
14
  # @return [Date] when the term starts
14
- # @!attribute [r] end
15
- # @return [Date] when the term ends
16
-
17
- # Initialize a new Term
18
- # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
19
- def initialize(attributes={})
20
- raise ArgumentError, ':id must be nil or a Fixnum > 0' unless attributes[:id].nil? || (attributes[:id].is_a?(Fixnum) && attributes[:id] > 0)
21
- raise ArgumentError, ':section_id must be nil or a Fixnum > 0' unless attributes[:section_id].nil? || (attributes[:section_id].is_a?(Fixnum) && attributes[:section_id] > 0)
22
- raise ArgumentError, ':name must be nil or a String' unless attributes[:name].nil? || attributes[:name].is_a?(String)
23
- raise ArgumentError, ':start must be nil or a Date' unless attributes[:start].nil? || attributes[:start].is_a?(Date)
24
- raise ArgumentError, ':end must be nil or a Date' unless attributes[:end].nil? || attributes[:end].is_a?(Date)
25
-
26
- attributes.each { |k,v| instance_variable_set("@#{k}", v) }
27
- end
15
+ # @!attribute [rw] finish
16
+ # @return [Date] when the term finishes
17
+
18
+ attribute :id, :type => Integer
19
+ attribute :section_id, :type => Integer
20
+ attribute :name, :type => String
21
+ attribute :start, :type => Date
22
+ attribute :finish, :type => Date
23
+
24
+ attr_accessible :id, :section_id, :name, :start, :finish
25
+
26
+ validates_numericality_of :id, :only_integer=>true, :greater_than=>0
27
+ validates_numericality_of :section_id, :only_integer=>true, :greater_than=>0
28
+ validates_presence_of :name
29
+ validates_presence_of :start
30
+ validates_presence_of :finish
31
+
32
+
33
+ # @!method initialize
34
+ # Initialize a new Term
35
+ # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
28
36
 
29
37
 
30
38
  # Initialize a new Term from api data
@@ -35,7 +43,7 @@ module Osm
35
43
  :section_id => Osm::to_i_or_nil(data['sectionid']),
36
44
  :name => data['name'],
37
45
  :start => Osm::parse_date(data['startdate']),
38
- :end => Osm::parse_date(data['enddate']),
46
+ :finish => Osm::parse_date(data['enddate']),
39
47
  )
40
48
  end
41
49
 
@@ -43,39 +51,39 @@ module Osm
43
51
  # @param [Date] date
44
52
  # @return [Boolean] if the term is completly before the passed date
45
53
  def before?(date)
46
- return @end < date.to_date
54
+ return finish < date.to_date
47
55
  end
48
56
 
49
57
  # Determine if the term is completly after the passed date
50
58
  # @param [Date] date
51
59
  # @return [Boolean] if the term is completly after the passed date
52
60
  def after?(date)
53
- return @start > date.to_date
61
+ return start > date.to_date
54
62
  end
55
63
 
56
64
  # Determine if the term is in the future
57
65
  # @return [Boolean] if the term starts after today
58
66
  def future?
59
- return @start > Date.today
67
+ return start > Date.today
60
68
  end
61
69
 
62
70
  # Determine if the term is in the past
63
71
  # @return [Boolean] if the term finished before today
64
72
  def past?
65
- return @end < Date.today
73
+ return finish < Date.today
66
74
  end
67
75
 
68
76
  # Determine if the term is current
69
77
  # @return [Boolean] if the term started before today and finishes after today
70
78
  def current?
71
- return (@start <= Date.today) && (@end >= Date.today)
79
+ return (start <= Date.today) && (finish >= Date.today)
72
80
  end
73
81
 
74
82
  # Determine if the provided date is within the term
75
83
  # @param [Date] date the date to test
76
84
  # @return [Boolean] if the term started before the date and finishes after the date
77
85
  def contains_date?(date)
78
- return (@start <= date) && (@end >= date)
86
+ return (start <= date) && (finish >= date)
79
87
  end
80
88
 
81
89
  def <=>(another_term)
@@ -100,6 +108,6 @@ module Osm
100
108
  end
101
109
  end
102
110
 
103
- end
111
+ end # Class Term
104
112
 
105
- end
113
+ end # Module
@@ -20,6 +20,8 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_runtime_dependency 'activesupport', '>= 3.2' # Used to parse JSON from OSM
22
22
  s.add_runtime_dependency 'httparty' # Used to make web requests to the API
23
+ s.add_runtime_dependency 'active_attr'
24
+ s.add_runtime_dependency 'activemodel'
23
25
 
24
26
  s.add_development_dependency 'rake'
25
27
  s.add_development_dependency 'rspec'
@@ -86,6 +86,8 @@ describe "Activity" do
86
86
  activity.badges[0].badge.should == 'badge'
87
87
  activity.badges[0].requirement.should == 'col_name'
88
88
  activity.badges[0].label.should == 'This is a label'
89
+
90
+ activity.valid?.should be_true
89
91
  end
90
92
 
91
93
  end
@@ -8,13 +8,14 @@ describe "API Access" do
8
8
  data = {
9
9
  'apiid' => '1',
10
10
  'name' => 'Name',
11
- 'permissions' => {'permission' => '100'},
11
+ 'permissions' => {'permission' => '10'},
12
12
  }
13
13
  api_access = Osm::ApiAccess.from_api(data)
14
14
 
15
15
  api_access.id.should == 1
16
16
  api_access.name.should == 'Name'
17
- api_access.permissions.should == {:permission => 100}
17
+ api_access.permissions.should == {:permission => 10}
18
+ api_access.valid?.should be_true
18
19
  end
19
20
 
20
21
 
@@ -419,7 +419,7 @@ describe "API" do
419
419
  'token' => @api_config[:api_token],
420
420
  'userid' => 'user',
421
421
  'secret' => 'secret',
422
- 'eveningid' => nil, 'sectionid' => nil, 'meetingdate' => '2000-01-02', 'starttime' => nil,
422
+ 'eveningid' => 1, 'sectionid' => 2, 'meetingdate' => '2000-01-02', 'starttime' => nil,
423
423
  'endtime' => nil, 'title' => 'Unnamed meeting', 'notesforparents' =>'', 'prenotes' => '',
424
424
  'postnotes' => '', 'games' => '', 'leaders' => '', 'activity' => '[]',
425
425
  }
@@ -427,7 +427,7 @@ describe "API" do
427
427
  api.stub(:get_terms) { [] }
428
428
  HTTParty.should_receive(:post).with(url, {:body => post_data}) { DummyHttpResult.new(:response=>{:code=>'200', :body=>'{"result":0}'}) }
429
429
 
430
- evening = Osm::Evening.new({:meeting_date => Date.new(2000, 01, 02)})
430
+ evening = Osm::Evening.new(:id=>1, :section_id=>2, :meeting_date=>Date.new(2000, 01, 02))
431
431
  api.update_evening(evening).should be_true
432
432
  end
433
433
 
@@ -438,7 +438,7 @@ describe "API" do
438
438
  'token' => @api_config[:api_token],
439
439
  'userid' => 'user',
440
440
  'secret' => 'secret',
441
- 'eveningid' => nil, 'sectionid' => nil, 'meetingdate' => '2000-01-02', 'starttime' => nil,
441
+ 'eveningid' => 1, 'sectionid' => 2, 'meetingdate' => '2000-01-02', 'starttime' => nil,
442
442
  'endtime' => nil, 'title' => 'Unnamed meeting', 'notesforparents' =>'', 'prenotes' => '',
443
443
  'postnotes' => '', 'games' => '', 'leaders' => '', 'activity' => '[]',
444
444
  }
@@ -446,10 +446,15 @@ describe "API" do
446
446
  api.stub(:get_terms) { [] }
447
447
  HTTParty.should_receive(:post).with(url, {:body => post_data}) { DummyHttpResult.new(:response=>{:code=>'200', :body=>'{"result":1}'}) }
448
448
 
449
- evening = Osm::Evening.new({:meeting_date => Date.new(2000, 01, 02)})
449
+ evening = Osm::Evening.new(:id=>1, :section_id=>2, :meeting_date=>Date.new(2000, 01, 02))
450
450
  api.update_evening(evening).should be_false
451
451
  end
452
- end
452
+
453
+ it "Update an evening (invalid evening)" do
454
+ api = Osm::Api.new('user', 'secret')
455
+ evening = Osm::Evening.new
456
+ expect{ api.update_evening(evening) }.to raise_error(Osm::ArgumentIsInvalid)
457
+ end end
453
458
 
454
459
 
455
460
  describe "Options Hash" do
@@ -52,6 +52,7 @@ describe "DueBadge" do
52
52
  db.descriptions.should == {:badge_name=>{:name=>"Badge Name", :section=>:cubs, :type=>:activity, :badge=>"badge_name"}, :cubs_core_participation=>{:name=>"Participation", :section=>:cubs, :type=>:core, :badge=>"participation"}}
53
53
  db.by_member.should == {"John Doe"=>[{:badge=>:badge_name, :extra_information=>""}, {:badge=>:cubs_core_participation, :extra_information=>"Lvl 2"}], "Jane Doe"=>[{:badge=>:cubs_core_participation, :extra_information=>"Lvl 3"}]}
54
54
  db.totals.should == {:badge_name=>{""=>1}, :cubs_core_participation=>{"Lvl 3"=>1, "Lvl 2"=>1}}
55
+ db.valid?.should be_true
55
56
  end
56
57
 
57
58
  end
@@ -6,7 +6,7 @@ describe "Evening" do
6
6
 
7
7
  before :each do
8
8
  @attributes = {
9
- :evening_id => 1,
9
+ :id => 1,
10
10
  :section_id => 2,
11
11
  :title => 'Evening Name',
12
12
  :notes_for_parents => 'Notes for parents',
@@ -15,7 +15,7 @@ describe "Evening" do
15
15
  :post_notes => 'After',
16
16
  :leaders => 'Leaders',
17
17
  :start_time => '19:00',
18
- :end_time => '21:00',
18
+ :finish_time => '21:00',
19
19
  :meeting_date => Date.new(2000, 01, 02),
20
20
  }
21
21
  end
@@ -42,7 +42,7 @@ describe "Evening" do
42
42
  }]
43
43
  e = Osm::Evening.from_api(data, activities)
44
44
 
45
- e.evening_id.should == 1
45
+ e.id.should == 1
46
46
  e.section_id.should == 2
47
47
  e.title.should == 'Evening Name'
48
48
  e.notes_for_parents.should == 'Notes for parents'
@@ -51,30 +51,15 @@ describe "Evening" do
51
51
  e.post_notes.should == 'After'
52
52
  e.leaders.should == 'Leaders'
53
53
  e.start_time.should == '19:00'
54
- e.end_time.should == '21:00'
54
+ e.finish_time.should == '21:00'
55
55
  e.meeting_date.should == Date.new(2000, 1, 2)
56
56
 
57
57
  ea = e.activities[0]
58
58
  ea.activity_id.should == 2
59
59
  ea.title.should == 'Activity Name'
60
60
  ea.notes.should == 'Notes'
61
- end
62
-
63
-
64
- it "Raises exceptions when trying to set invalid times" do
65
- e = Osm::Evening.new(@attributes)
66
-
67
- expect{ e.start_time = 'abcde' }.to raise_error(ArgumentError)
68
- expect{ e.start_time = '24:00' }.to raise_error(ArgumentError)
69
- expect{ e.start_time = '10:61' }.to raise_error(ArgumentError)
70
- e.start_time = '12:34'
71
- e.start_time.should == '12:34'
72
61
 
73
- expect{ e.end_time = 'abcde' }.to raise_error(ArgumentError)
74
- expect{ e.end_time = '24:00' }.to raise_error(ArgumentError)
75
- expect{ e.end_time = '10:61' }.to raise_error(ArgumentError)
76
- e.end_time = '23:45'
77
- e.end_time.should == '23:45'
62
+ e.valid?.should be_true
78
63
  end
79
64
 
80
65