Create contact book model

This commit is contained in:
2025-09-23 11:11:49 +02:00
parent 7432a46ae2
commit 16f58323aa
8 changed files with 286 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
"
I represent a person with a name and an email address. I'm usually
part of a contact book.
"
Class {
#name : #Contact,
#superclass : #Object,
#instVars : [
'fullname',
'email'
],
#category : #ContactBook
}
{ #category : #'instance creation' }
Contact class >> newNamed: aNameString email: anEmailString [
^ self new
fullname: aNameString;
email: anEmailString;
yourself
]
{ #category : #accessing }
Contact >> email [
^ email
]
{ #category : #accessing }
Contact >> email: anObject [
email := anObject
]
{ #category : #accessing }
Contact >> fullname [
^ fullname
]
{ #category : #accessing }
Contact >> fullname: aString [
fullname := aString
]
{ #category : #accessing }
Contact >> printOn: aStream [
aStream
nextPutAll: self fullname;
nextPutAll: ' <';
nextPutAll: self email;
nextPutAll: '>'
]

View File

@@ -0,0 +1,44 @@
Class {
#name : #ContactBook,
#superclass : #Object,
#instVars : [
'contacts'
],
#category : #ContactBook
}
{ #category : #demos }
ContactBook class >> createDefault [
^ self new
addContact: (Contact newNamed: 'Damien Cassou' email: 'damien@cassou.me');
addContact: (Contact newNamed: 'Marcus Denker' email: 'marcus.denker@inria.fr');
addContact: (Contact newNamed: 'Tudor Girba' email: 'tudor@tudorgirba.com');
addContact: (Contact newNamed: 'Clara Allende' email: 'clari.allende@gmail.com');
yourself
]
{ #category : #writing }
ContactBook >> addContact: aContact [
self contacts add: aContact
]
{ #category : #reading }
ContactBook >> contacts [
^ contacts
]
{ #category : #initialization }
ContactBook >> initialize [
super initialize.
contacts := OrderedCollection new
]
{ #category : #deleting }
ContactBook >> removeContact: aContact [
self contacts remove: aContact
]
{ #category : #initialization }
ContactBook >> size [
^ contacts size
]

View File

@@ -0,0 +1,40 @@
Class {
#name : #ContactBookTest,
#superclass : #TestCase,
#instVars : [
'blog',
'post'
],
#category : #ContactBook
}
{ #category : #running }
ContactBookTest >> setUp [
blog := ContactBook new.
blog addContact: (Contact newNamed: 'Tudor Girba' email: 'tudor@tudorgirba.com').
post := Contact newNamed: 'Clara Allende' email: 'clari.allende@gmail.com'
]
{ #category : #tests }
ContactBookTest >> testAddContact [
blog addContact: post.
self assert: blog size equals: 2
]
{ #category : #tests }
ContactBookTest >> testContacts [
blog addContact: post.
self assert: blog contacts size equals: 2
]
{ #category : #tests }
ContactBookTest >> testRemoveContact [
blog removeContact: blog contacts first.
self assert: blog size equals: 0
]
{ #category : #tests }
ContactBookTest >> testSize [
self assert: blog size equals: 1
]

View File

@@ -0,0 +1,26 @@
Class {
#name : #ContactTest,
#superclass : #TestCase,
#category : #ContactBook
}
{ #category : #tests }
ContactTest >> testCreation [
| contact |
contact := Contact
newNamed: 'Marcus Denker'
email: 'marcus.denker@inria.fr'.
self assert: contact fullname equals: 'Marcus Denker'.
self assert: contact email equals: 'marcus.denker@inria.fr'
]
{ #category : #tests }
ContactTest >> testPrinting [
| contact |
contact := Contact
newNamed: 'Marcus Denker'
email: 'marcus.denker@inria.fr'.
self assert: contact asString equals: 'Marcus Denker <marcus.denker@inria.fr>'
]

View File

@@ -0,0 +1,23 @@
Class {
#name : #TBHeaderComponent,
#superclass : #WAComponent,
#category : #ContactBook
}
{ #category : #rendering }
TBHeaderComponent >> renderBrandOn: html [
html tbsNavbarHeader: [
html tbsNavbarBrand
url: self application url;
with: 'TinyBlog'
]
]
{ #category : #rendering }
TBHeaderComponent >> renderContentOn: html [
html tbsNavbar beDefault; with: [
html tbsContainer: [
self renderBrandOn: html
]
]
]

View File

@@ -0,0 +1,36 @@
Class {
#name : #TBScreenComponent,
#superclass : #WAComponent,
#instVars : [
'header'
],
#category : #ContactBook
}
{ #category : #acccessing }
TBScreenComponent >> blog [
"Return the current blog. In the future we will ask the
session to return the blog of the currently logged in user."
^ ContactBook current
]
{ #category : #acccessing }
TBScreenComponent >> children [
^ { header }
]
{ #category : #initialization }
TBScreenComponent >> createHeaderComponent [
^ TBHeaderComponent new
]
{ #category : #initialization }
TBScreenComponent >> initialize [
super initialize.
header := self createHeaderComponent
]
{ #category : #acccessing }
TBScreenComponent >> renderContentOn: html [
html render: header
]

View File

@@ -0,0 +1,62 @@
Class {
#name : #WAContactBook,
#superclass : #WAComponent,
#instVars : [
'contactBook'
],
#category : #ContactBook
}
{ #category : #initialization }
WAContactBook class >> initialize [
WAAdmin register: self asApplicationAt: 'contacts'.
]
{ #category : #accessing }
WAContactBook >> contactBook [
^ contactBook ifNil: [ contactBook := ContactBook createDefault ]
]
{ #category : #accessing }
WAContactBook >> contacts [
^ self contactBook contacts
]
{ #category : #iterating }
WAContactBook >> contactsDo: aBlock [
self contacts do: aBlock
]
{ #category : #rendering }
WAContactBook >> renderContact: aContact on: html [
html tableRow: [
html
tableData: aContact fullname;
tableData: aContact email ]
]
{ #category : #rendering }
WAContactBook >> renderContactsOn: html [
html table: [
html tableHead: [
html
tableHeading: 'Name';
tableHeading: 'Email' ].
self contactsDo: [ :contact | self renderContact: contact on: html ] ]
]
{ #category : #rendering }
WAContactBook >> renderContentOn: html [
"Main entry point of the view. Render both a title and the list of contacts."
html heading
level: 1;
with: 'My Contact Book'.
self renderContactsOn: html
]
{ #category : #updating }
WAContactBook >> updateRoot: anHtmlRoot [
super updateRoot: anHtmlRoot.
anHtmlRoot title: 'Contact Book'
]

View File

@@ -0,0 +1 @@
Package { #name : #ContactBook }